个性化阅读
专注于IT技术分析

如何在JavaScript的回调中正确地访问“this”?

现在有一个构造函数,里面注册了一个事件处理器:

function Constructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

var obj = new Constructor('foo', transport);

但是在回调函数中无法访问对象的data属性,看起来不是指向创建的对象,而是另一个对象。

如果不使用匿名函数,使用对象方法如下:

function Constructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

Constructor.prototype.alert = function() {
    alert(this.name);
};

但是也出现了相同的问题,如何才能访问到正确的对象?

关于this

This是每个函数中的一个特殊的关键字,它的值只取决于函数是如何调用的,而不是如何/何时/何地定义的。它不像其他变量一样受词法范围的影响(箭头函数除外,见下文)。下面是一些例子:

function foo() {
    console.log(this);
}

// 普通函数调用
foo(); // this指的是`window`对象

//作为对象函数
var obj = {bar: foo};
obj.bar(); // 这里的this指的是对象`

//作为构造函数
new foo(); // this为该对象

如何正确地使用this

不要使用this

实际上你并不需要访问this,而是它引用的对象。这就是为什么一个简单的解决方案是创建一个新的变量,它也引用那个对象。变量可以有任何名称,但常见的名称是self等等:

function Constructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

由于self是一个普通变量,所以它遵守词法作用域规则,并且可以在回调函数中访问。这还有一个好处,你可以访问回调本身的这个值。

显示地设置回调函数的this

你可能无法控制this值,因为它的值是自动设置的,但实际情况并非如此。每个函数都有.bind方法,该方法返回一个新函数,并将其绑定到一个值。该函数具有与你调用.bind的函数完全相同的行为,只是这是你设置的。无论如何或何时调用该函数,它总是引用传递的值。

function Constructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { 
        alert(this.data);             
    }).bind(this); 
    transport.on('data', boundFunction);
}

在本例中,我们将回调函数的this绑定到Constructor的this的值。注意:当为jQuery绑定上下文时,使用jQuery.proxy这样做的原因是,在解绑定事件回调时,不需要存储对函数的引用。jQuery在内部处理这个问题。

ECMAScript6: 使用箭头函数

一些接受回调的函数/方法也接受这个回调应该引用的值。这基本上与你自己绑定它是一样的,但是函数/方法为你完成了这一点。Array#map就是这样一个方法。它的特征是:array.map(callback [, thisArg])。

第一个参数是回调函数,第二个参数是this该引用的值,下面是一个常见的例子:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj);
赞(0)
未经允许不得转载:srcmini » 如何在JavaScript的回调中正确地访问“this”?

评论 抢沙发

评论前必须登录!