话不多说,直接先来看几个函数调用的场景
function foo() {
console.log(this.a);
};
let a = 1;
foo();
const obj = {
a: 2,
foo: foo
};
obj.foo();
const c = new foo();
接下来一个个分析上面的场景
-
对于直接调用foo来说,不管foo函数被放在了什么地方,this 一定是指向 window
-
对于obj.foo()来说,只需记住,谁调用了函数,谁就是this,所以在这个场景下foo函数中的this就是obj对象
-
对于new来说,this被永远绑定在了c上面,不会被任何方式改变this
再来看看箭头函数中的this
function a() {
return () => {
return ()=> {
console.log(this);
};
};
};
console.log(a()()());
首先箭头函数其实是没有this的,箭头函数中的this只取决于包裹箭头函数的第一个普通函数的this。在上面这个例子中,因为包裹箭头函数的第一个普通函数就是a,所以此时的this是window。另外对箭头函数使用bind这类函数是无效。
最后情况也就是bind这些改变上下文API了,对于这些函数来说,this取决于第一个参数,如果第一个参数为空,那么就是window。
如果对一个函数进行多次bind的情况下
let a = {};
let fn = function() { console.log(this) };
fn.bind().bind(a)() // => 打印出什么?
其实可以把上诉代码转换成另一种形式
let fn2 = function fn1() {
return function() {
return fn.apply()
}.apply(a)
};
fn2();
可以从上诉代码中发现,不管我们给函数bind几次,fn中的this永远由第一次bind决定,所以结果永远是window。
let a = { name: 'xyz' };
function foo() {
console.log(this.name);
};
foo.bind(a)(); // => 'xyz'
当多个规则同时出现的情况,这时候不同的规则之间会根据优先级最高的来决定this最终指向哪里。
首先,new方式优先级别最高,接下来是bind这些函数,然后是obj.foo()这种调用方式,最后是foo这种调用方式,同时,箭头函数的this一旦被绑定,就不会再被任何方式改变。
最后是关于this指向的流程图,帮助梳理思路(只针对于单个规则)
---END---