这是我参与「第四届青训营 」笔记创作活动的第4天
this指向一直是经常遇到的问题,特别是在ES6之后,关于this的指向就更加的疑惑,所以今天把this指向整理一下。
普通函数
普通函数的this通常是指向最后调用它的对象的。
看一个例子
const a = {
name : 'Vicky',
fn:function(){
console.log(this.name);
}
}
a.fn();//Vicky
因为最后调用它的对象是对象a,所以this指向的a。
function foo(){
console.log(this);
}
foo(); //window
这个例子当中相当于是window.foo(),所以this指向的就会是全局对象window。
注:如果是使用的严格模式的话,输出的对象会是undefine
看了这两个例子之后对于this指向最后一个调用它的对象就很清晰明了了。如若第一个例子改成window.a.fn(),输出也是保持不变的,因为最后调用它的对象为a。
将第一个例子改变一下:
var name = "Mary";
const a = {
name : 'Vicky',
fn:function(){
console.log(this.name);
}
}
const foo = a.fn;
foo();//Mary
这是为什么呢,因为在foo = a.fn的时候,fn并没有被调用,而是作为了一个方法赋值给了foo,当foo()的时候,fn才真正被调用,所以相当于window.foo(),this指向的是最后调用它的全局变量window。
在掘金上还有看到一个大佬写的例子:
var name = "windowsName";
function fn()
{
var name = 'Cherry';
innerFunction();
function innerFunction()
{
console.log(this.name); // windowsName
}
}
fn()
\
作者:sunshine小小倩\
链接:https://juejin.cn/post/6844903496253177863\
来源:稀土掘金\
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
最后输出的是"windowsName",而不是"Cherry",因为虽然innerFunction函数在fn函数里面,但是它在作为函数被调用的时候,没有挂在任何的对象上,也就是说,它在fn函数里被调用时是window.innerFunction()状态的,所以它的this应该指向的是全局对象window。
箭头函数
我们都知道,ES6的箭头函数是没有this绑定的,所以它的this指向与普通函数有点差异。
在普通函数里,this的指向是在执行的时候确定的,而不是在函数定义的时候就定下的,它可以根据调用函数执行时候的不同更改this指向
但是在箭头函数里,this的指向是在函数定义的时候定下的,而不是执行时,并且箭头函数this指向要通过它的作用域逐层向上寻找。
可以看一个例子:
var name = "aaa";
var a = {
name : "bbb",
foo : function(){
setTimeout(function(){
console.log(this.name);//aaa
},1000)
}
}
a.foo();
这个是个普通函数,可以发现this是指向window的,和我们的普通函数最后一个例子的原理差不多,相当于setTimeOut里面的匿名函数它在被调用的时候,调用的对象相当于是全局对象window,所以this指向的是window。也可以理解为"匿名函数的this指向永远都是window"。
var name = "aaa";
var a = {
name : "bbb",
foo : function(){
setTimeout(() => {
console.log(this.name);//bbb
},1000)
}
}
a.foo();
箭头函数在函数定义的时候通过查找作用域链,决定this.name的值为"bbb"。
很好理解的就是,箭头函数的this绑定的就是最近一层非箭头函数的this。
apply、call、bind
这三个函数都是可以改变this的指向,但是请注意,箭头函数的this是不可更改的,只能改变普通函数的this。
联系与区别
-
三个函数的第一个参数都是指定函数内部的
this指向,然后根据指定的作用域,调用该函数。如果为null或者undefine,则this指向全局对象 -
除了
apply第二个参数是传入一个参数数组外,call和bind可以直接传入,(第二个参数即调用的函数的参数),如果第二参数为undefine或者null,则表示没有参数传入函数 -
call和apply函数可以直接调用执行,但bind函数是返回的一个函数,所以还要再执行一遍,如b.bind(a)()