在JavaScript中,每个函数都有this
引用在声明它自动创建。该参考颇为相似, this
在其他基于类的语言如Java或C#参考(JavaScript是一种基于原型的语言,并没有“阶级”的概念): 它指向哪个对象有时调用的函数 (该对象称为上下文 )。但是,在JavaScript中, 函数内部的this
引用可以绑定到不同的对象,具体取决于调用函数的位置 。以下是JavaScript中this
绑定的5个基本规则:
规则1
在全局范围中调用函数时, this
引用默认绑定到全局对象 (浏览器中的window
或Node.js中的global
)。例如:
function foo() {
this.a = 2;
}
foo();
console.log(a); // 2
注意:如果在严格模式下声明上面的foo()
函数,那么在全局范围内调用此函数, this
将是undefined
并且赋值this.a = 2
将抛出Uncaught TypeError
异常。
规则2
我们来看下面的例子:
function foo() {
this.a = 2;
}
var obj = {
foo: foo
};
obj.foo();
console.log(obj.a); // 2
显然,在上面的代码片段中, foo()
函数被调用, _上下文_是obj
对象,现在this
引用绑定到obj
。因此,当使用上下文对象调用函数时, this
引用将绑定到此对象。
规则3
.call
, .apply
和.bind
都可以在调用点使用显式绑定this
。使用.bind(this)
是你可以在很多React组件中看到的东西。
var foo = function() {
console.log(this.bar)
}
foo.call({ bar: 1 }) // 1
这是一个快速的例子,说明如何使用每个绑定this
:
fn.call(thisObj, fnParam1, fnParam2)
.call()
:fn.call(thisObj, fnParam1, fnParam2)
.apply()
:fn.apply(thisObj, [fnParam1, fnParam2])
.bind()
:const newFn = fn.bind(thisObj, fnParam1, fnParam2)
规则4
function Point2D(x, y) {
this.x = x;
this.y = y;
}
var p1 = new Point2D(1, 2);
console.log(p1.x); // 1
console.log(p1.y); // 2
您必须注意的是使用new
关键字调用的Point2D
函数,并且this
引用绑定到p1
对象。因此,当使用new
关键字调用函数时,它将创建一个新对象,并且this
引用将绑定到此对象。
注意:当您使用new
关键字调用函数时,我们也将其称为构造函数 。
规则5
的JavaScript确定的值this
在运行时,基于所述当前上下文。所以this
有时会指向你期望的东西。
考虑这个带有一个名为makeSound()
的方法的Cat类示例,遵循规则4(上面)中的模式,带有构造函数和new
关键字。
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.makeSound(); // Fat Daddy says: Mrrooowww
现在让我们试着给猫一个方法来annoy()
人们通过重复他的声音100次,每半秒一次。
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var t = setInterval(function() {
this.makeSound(); // <-- this line fails with `this.makeSound is not a function`
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
这不起作用,因为在setInterval
回调中我们创建了一个具有全局范围的新上下文,所以this
不再指向我们的kitty实例。在Web浏览器中, this
将指向Window对象,该对象没有makeSound()
方法。
有几种方法可以使它工作:
1)创建新的上下文之前,分配this
名为局部变量me
,或self
,或任何你想将它命名,并使用回调内部的变量。
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var self = this;
var t = setInterval(function() {
self.makeSound();
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
2)同ES6就可以避免分配this
通过使用箭头功能,其结合本地变量this
到它的限定的周围的代码的情况下。
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var t = setInterval(() => {
this.makeSound();
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
更多JavaScript教程
学习更多JavaScript教程