首先明确,作用域链和 this 是两套不同的系统,它们之间基本没太多联系
极客时间-《浏览器的工作原理与实践》-[浏览器中的 JavaScript 执行机制]
---11.this:从JavaScript执行上下文的视角讲清楚this
《你不知道的JavaScript》(上卷) 中对 this 的相关介绍:
# 分类
- 全局执行上下文中的 this,指向 window 对象
- 函数执行上下文中的 this,
- 通过函数的 call/apply/bind 方法设置,this 指向 call/apply/bind 方法中的第一个参数
- 通过对象调用方法设置,this 指向对象本身
- 通过构造函数中设置,this 指向 new 的实例对象
- eval 中的 this
# this 的设计缺陷以及应对方案
- 嵌套函数中的 this 不会从外层函数中继承
- 在函数中声明一个变量 self 用来保存 this
- 使用 ES6 中的箭头函数,这是因为 ES6 中的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的 this 取决于它的外部函数
- 普通函数中的 this 默认指向全局对象 window
- 如果要让函数执行上下文中的 this 指向某个对象,最好的方式是通过 call 方法来显示调用。
- 通过设置 JavaScript 的“严格模式”,在严格模式下,默认执行一个函数,其函数的执行上下文中的 this 值是 undefined
# 判断this
可以参考 yck《前端面试手册》中的建议:
# 小结
推荐练习: 再来40道this面试题酸爽继续(1.2w字用手整理) (opens new window)
练习题得重复看几次:
- 3.2
- 3.3
- 3.4
- 4.2
- 4.3
- 7.3
- 8.3
- 8.4
箭头函数部分总结
7.箭头函数部分
- 如果箭头函数外面是一个定义在window下的字面量对象,则箭头函数的this指向window;--> 7.6
- 如果箭头函数外面是一个非箭头函数包裹着,箭头函数的this就是函数部分的this??? --> 7.5
- 7.3
OK👌,来总结一下箭头函数需要注意的点吧:
- 它里面的this是由外层作用域来决定的,且指向函数定义时的this而非执行时
- 字面量创建的对象,作用域是window,如果里面有箭头函数属性的话,this指向的是window
- 构造函数创建的对象,作用域是可以理解为是这个构造函数,且这个构造函数的this是指向新建的对象的,因此this指向这个对象。
- 箭头函数的this是无法通过bind、call、apply来直接修改,但是可以通过改变作用域中this的指向来间接修改。
优点
- 箭头函数写代码拥有更加简洁的语法(当然也有人认为这是缺点)
- this由外层作用域决定,所以在某些场合我们不需要写类似const that = this这样的代码
避免使用的场景
根据箭头函数的特性,所以我们应该避免在以下四种场景中使用它:
- 使用箭头函数定义对象的方法
let obj = {
value: 'LinDaiDai',
getValue: () => console.log(this.value)
}
obj.getValue() // undefined
1
2
3
4
5
2
3
4
5
- 定义原型方法
function Foo (value) {
this.value = value
}
Foo.prototype.getValue = () => console.log(this.value)
const foo1 = new Foo(1)
foo1.getValue() // undefined
1
2
3
4
5
6
7
2
3
4
5
6
7
- 构造函数使用箭头函数
const Foo = (value) => {
this.value = value;
}
const foo1 = new Foo(1)
// 事实上直接就报错了 Uncaught TypeError: Foo is not a constructor
console.log(foo1);
1
2
3
4
5
6
2
3
4
5
6
- 作为事件的回调函数
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
1
2
3
4
5
2
3
4
5