初识 this 关键字
this 是个特殊的关键字,被自动定义在所有函数的作用域中。假设我们要写一个 sayName 函数,应该是这样写的:
function sayName(who) {
console.log(who.name);
}
var me = {
name: 'Lwenn';
}
var you = {
name: 'Nana';
}
sayName(me); // Lwenn
sayName(you); // Nana
上面的 sayName 需要显式传入一个对象引用,现在有 this 了,我们可以用 this 改写上面的代码:
function sayName() {
console.log(this.name);
}
var me = {
name: 'Lwenn';
}
var you = {
name: 'Nana';
}
sayName.call(me); // Lwenn
sayName.call(you); // Nana
可以看出,this 提供了一种隐式传递一个对象引用的方式,注意到这里用了 call,为什么这样写,之后会讲到。
this 绑定规则
每个函数的 this 是在函数调用时被绑定的,所以 this 的绑定和函数被调用的位置有关。this 有四种绑定规则。
默认绑定
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2 <-- foo的调用位置
当调用 foo() 时,调用位置是全局作用域,由于函数调用时应用了 this 的默认绑定,所以 this 指向全局对象。
注:如果使用严格模式,全局对象将无法使用默认绑定,因此 this 会绑定到 undefined。
隐式绑定
隐式绑定是在一个对象内部包含一个指向函数的属性,通过这个属性引用函数从而把 this 绑定到这个对象上。
var obj = {
a: 2,
foo: function() {
console.log(this.a);
}
}
obj.foo(); // 2
在这里 foo() 的调用位置会使用 obj 的上下文来引用函数。当函数引用有上下文对象时,会应用隐式绑定把函数中的 this 绑定到这个上下文对象。所以 foo() 中的 this 指向的是 obj。
多层属性引用
对象属性引用链中只有最后一层会影响调用位置。
var obj = {
a: 2,
foo: function() {
console.log(this.a);
}
}
var obj2 = {
a: 3,
obj: obj
}
obj2.obj.foo(); // 2
foo() 中的 this 还是指向 obj,即引用链最后一层。
隐式丢失
隐式丢失是指被隐式绑定的函数丢失绑定对象,它会应用默认绑定。
var obj = {
a: 2,
foo: function() {
console.log(this.a);
}
}
var bar = obj.foo;
bar(); // undefined
(0, obj.foo)(); // undefined
bar 是 obj.foo 的一个引用,而 this 是在函数调用时绑定的,当调用 bar() 时应用了默认绑定,进而把 this 绑定到全局对象,而全局对象没有 a 属性。
同理,(0, obj.foo) 是运用逗号表达式返回了一个 obj.foo 的引用。
显式绑定
如果想在对象上强制调用不属于这个对象属性的函数,可以使用显式绑定。JavaScript 提供了这些 API。
- call
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 2
- apply
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.apply(obj); // 2
apply 和 call 的区别在于参数形式。
- bind
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
var bar = foo.bind(obj);
bar(); // 2
这里的 bar 虽然是 foo 的一个引用,但是它的 this 已经绑定到 obj 上了。
new 绑定
在 JavaScript 中,称作构造函数的函数可以被 new 操作符调用,不过它们实际上和普通函数没有区别。当函数被 new 调用时,会创建一个新对象,并且把函数调用的 this 绑定到这个新对象。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
this 与箭头函数
ES6 中新增了特殊的函数类型:箭头函数。它不使用 this 的四种绑定规则,而是根据词法作用域来决定 this。
箭头函数最常用于回调函数中,例如事件处理器、定时器。
var obj = {
a: 2,
foo: function () {
setTimeout(() => {
console.log(this.a);
}, 100);
}
}
obj.foo(); // 2
如果不使用箭头函数,就需要用变量把 this 存起来,或者使用绑定规则改变回调函数的 this。所以箭头函数的 this 是特别的。
本文详细解析了JavaScript中的this关键字,包括其绑定规则、默认绑定、隐式绑定、显式绑定及new绑定等内容,并对比了箭头函数中的this行为。
2951

被折叠的 条评论
为什么被折叠?



