对 this 指向的理解
上周卓动的面试中,面试官提到了普通函数和箭头函数的区别,当时面试前准备的很不充分,是这么回答他的" 箭头函数和普通函数的最明显区别就是在代码上面的书写格式,箭头函数与普通函数写法上比起来更加简洁,其次是二者当中的 this 关键字指向不同(当时其实我是不知道二者的 this 指向具体有哪些不同的,最后面试官让我具体展开说说,我就直接寄了) "后面回来只能狠狠滴恶补。
this 的指向:
普通函数:
在 ES5 中,或者狭义一点,在普通函数当中,this 关键字指向的永远都是 "最后调用它的那个对象",最简单的例子:
var name = 'GGBond';
function fn() {
var name = 'PandaGuo';
console.log(this.name);
}
fn(); // GGBond
上述代码中,最后调用函数 fn 的地方是 fn(),而在非严格模式下,函数调用没有前缀的情况下,会默认绑定指向全局对象** window**,所以此刻的 fn() 就相当于 window.fn(),那么最后调用的对象就是 window。
再对上述代码进行部分修改:
var name = 'GGBond';
var student = {
name: 'PandaGuo',
fn: function() {
console.log(this.name);
}
}
var fn2 = student.fn;
student.fn(); // PandaGuo
window.student.fn(); // PandaGuo
fn2(); // GGBond
上述代码中,student.fn() 表明了前面的调用对象是 student,所以 this 指向会隐式绑定到 student 上;而 window.student.fn() 当中,无论前面调用的对象有多少个,都指向最后一个调用对象,所以这里的 this 也是隐式绑定到最后一个对象 student 上;对与 fn2() 为何最终打印出来的是 "GGBond" ?其实这里面有坑:虽然将 student 对象当中的 fn 方法 赋值给 fn2,但是没有进行调用,根据上述 " this 关键字指向永远都是最后调用它的那个对象 " ,fn2 没用调用,所以 fn 方法最后的调用对象还会是 window 。
再对代码进行部分修改:
var name = 'GGBond';
var student = {
// name: 'PandaGuo',
fn: function() {
console.log(this.name);
}
}
student.fn(); // undefined
将 student 对象中的 name 属性注释掉,最终 fn 方法打印出来的是 undefined,因为 " this 关键字指向永远都是最后调用它的那个对象 ",所以最终是 student 对象调用了 fn 方法,而 student 中没有对 name 进行定义,所以最终输出结果为 undefined 。
箭头函数:
在 ES6 的箭头函数当中没有自己的 this 绑定,它会继承上一层作用域的 this 对象,其 this 的指向取决于函数定义时的上下文环境,而不是函数调用时的环境,也就是说,当箭头函数被定义时,其 this 的指向就已经确定了(静态化),如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this。
举例:
var name = 'GGBond';
var student = {
name: 'PandaGuo',
fn: function() {
setTimeout(() => {
console.log(this.name);
}, 1000)
}
}
student.fn(); // PandaGuo
上述代码中 console.log(this.name) 写在箭头函数当中,而改箭头函数被 fn 定义的普通函数包含,则箭头函数 this 绑定了 fn 函数指向的 this,也就是 student 对象,故最终输出为 " PandaGuo "。
改变普通函数 this 指向的方法:
- 使用 ES6 箭头函数;
- 函数内部使用 _this = this;
- 使用 new 实例化对象;
- 使用 apply、call、bind
具体实现方法参考这篇文章:this、apply、call、bind - 掘金 (juejin.cn)
参考文章: