前言
在javascript
的开发中,经常会遇到this
这个关键字。简单的说this是个特殊变量。但是在javascript
中,this的使用经常让我感到困惑,这篇文章是阅读《你不知道的JavaScript》中第二章this的全面解析笔记。
调用位置
this
的绑定结果就是this在代码中调用的位置。注意是调用位置,而不是声明位置。如下面的代码:
var value = 'global';
var obj = {
value: 'obj',
foo: function() {
return this.value;
}
};
var bar = obj.foo;
console.log(bar());
console.log(obj.foo());
在这个例子中,函数 foo
是在 obj
对象的上下文中声明的,并且返回 this.value
。 this
在这个函数中应该引用其声明位置的上下文,即 obj
;然而 this
实际上引用了调用位置的上下文。我们可以通过比较 bar()
和 obj.foo()
的结果来观察这一点。
当我们只是简单地调用 bar()
时,this
被设置为全局对象(在浏览器中为 window
),因此 this.value
返回全局的 value
变量,即 'global'
。
然而,当我们调用 obj.foo()
时,this
被设置为 foo
函数被调用时的对象,即 obj
。因此 this.value
返回了 obj
的 value
属性,即 'obj'
。
绑定规则
this
的绑定规则为4种,分别如下:
- 默认绑定:这是最常见的绑定,当一个函数独立调用(不是作为对象的方法,作为回调等)时,
this
指向全局对象(在浏览器中为window
),但是如果在严格模式下,this
会被绑定到 'undefined'。
function show() {
console.log(this.a);
}
var a = 'Global';
show(); // 输出: 'Global'; 在非严格模式下
- 隐式绑定:当一个函数作为对象的方法调用时,
this
会被绑定到这个对象。这里注意的就是对象属性链只有最顶层或者说最后一层会影响调用位置。
var obj = {
a: 'Object',
show: function() {
console.log(this.a);
}
}
obj.show(); // 输出: 'Object'
- 显式绑定:可以使用
call
,apply
,bind
这些函数来显示的绑定this
。
function show() {
console.log(this.a);
}
var obj = {
a: 'Explicit'
};
show.call(obj); // 输出: 'Explicit',使用 call 函数显式绑定
new
绑定:当一个函数被new
关键字作为构造函数调用时,函数内部的this
会被绑定到新创建的对象。
function Show() {
this.a = 'New';
}
var newObj = new Show();
console.log(newObj.a); // 输出:'New'
优先级
- 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
var bar = new foo() - 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是
指定的对象。
var bar = foo.call(obj2) - 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上
下文对象。
var bar = obj1.foo() - 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到
全局对象。
var bar = foo()
规则总有例外,这里也一样。在某些场景下 this 的绑定行为会出乎意料,你认为应当应用其他绑定规则时,实际上应用的可能是默认绑定规则
箭头函数
箭头函数是一种特殊的函数类型,不是使用function
关键字定义的,也不使用this的四种规则标准。而是根据外层(函数或者全局)作用域决定的。箭头函数的绑定也无法修改(new也不行)。他的目的是取代this规则。这其实和 ES6 之前代码中的self = this
机制一样。
评论区