翻译自文章The Simple Rules to ‘this’ in Javascript。
确定什么是 this
并非难事。总的来说,通过查找函数被调用时的位置(和方法)就可以决定。遵循以下规则,按优先级排列。
规则
-
通过
new
关键字调用构造函数,函数内的this
是一个全新的对象。function ConstructorExample() { console.log(this); this.value = 10; console.log(this); } new ConstructorExample(); // -> {} // -> { value: 10 }
-
通过
apply
、call
或bind
调用一个函数,函数内的this
就是传入的参数。function fn() { console.log(this); } var obj = { value: 5 }; var boundFn = fn.bind(obj); boundFn(); // -> { value: 5 } fn.call(obj); // -> { value: 5 } fn.apply(obj); // -> { value: 5 }
-
如果一个函数作为对象的方法调用,即使用
.
符号调用该函数,this
是调用该函数的对象。换句话说,当.
处于被调用函数的左边,则this
就是左边的对象。var obj = { value: 5, printThis: function() { console.log(this); } }; obj.printThis(); // -> { value: 5, printThis: ƒ }
-
如果函数作为普通函数调用,意味着调用方式不符合以上任意一种,
this
就是全局对象。在浏览器中就是window
。function fn() { console.log(this); } // If called in browser: fn(); // -> Window {stop: ƒ, open: ƒ, alert: ƒ, ...}
*这个规则可以类比于规则3——不同之处在于这个函数自动挂载到了
window
对象上,所以可以这么理解,当我们调用fn()
时其实调用的事window.fn()
,所以this
就是window
。console.log(fn === window.fn); // -> true
- 如果符合上述多个规则,则越前面的规则会决定
this
的值。 -
如果函数是一个
ES2015
箭头函数,会忽略上述所有规则,this
设置为它被创建时的上下文。为了找到this
的值,需要找到函数被创建时的环境中this
的值。const obj = { value: 'abc', createArrowFn: function() { return () => console.log(this); } }; const arrowFn = obj.createArrowFn(); arrowFn(); // -> { value: 'abc', createArrowFn: ƒ }
我们返回去看规则3,当我们调用
obj.createArrowFn()
时,createArrowFn
中的this
就是obj
对象,我们用.
符号调用。如果我们在全局中创建一个箭头函数,this
就是window
。
应用规则
下面在几个例子中应用一下我们的规则。试一下通过两种不同的方式调用函数时 this
的值。
找到应用的规则
var obj = {
value: 'hi',
printThis: function() {
console.log(this);
}
};
var print = obj.printThis;
obj.printThis(); // -> {value: "hi", printThis: ƒ}
print(); // -> Window {stop: ƒ, open: ƒ, alert: ƒ, ...}
obj.printThis()
很显然应用的是规则3——使用 .
符号。 print()
应用了规则4,在调用 print()
时,我们没有使用 new
、 bind/call/apply
或 .
符号,所以这里的 this
是全局对象 window
。
多重规则应用
如上文提到,当应用多个规则时,优先应用前面的规则。
var obj1 = {
value: 'hi',
print: function() {
console.log(this);
},
};
var obj2 = { value: 17 };
如果规则2和3同时应用,规则2优先。
obj1.print.call(obj2); // -> { value: 17 }
如果规则1和3同时应用,规则1优先。
new obj1.print(); // -> {}
关于工具库
一些 JavaScript
库有时候会在函数中主动绑定它认为最有用的内容到 this
上。比如在 JQuery中,在触发事件时 DOM 元素被绑定到了 this
上。在使用工具库时发现取值不符合上述规则时,请查看库文档。很可能使用了 bind
语法。
该文章首发于我的个人站点
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。