前端面试问题(5 部分系列)
这是前端面试问题系列的第 5 个问题。如果您希望提高准备水平或保持最新状态,请考虑注册前端训练营。
this
关键字始终引用函数或脚本的当前上下文。
this
对于我们大多数人来说是一个令人困惑的话题(双关语),但事实并非如此。您所需要做的就是记住一些规则。
以下规则(按优先顺序排列)规定了在运行时如何确定 this
的值:
在函数构造函数中的用法
如果使用关键字调用函数,则函数内部引用新创建的对象实例。
function Book(title) {
console.log(this);
this.title = title;
console.log(this);
}
const book1 = new Book('Jungle Book');
// {}
// { title: "'Jungle Book' }"
console.log(book1.title); // 'Jungle Book'
显式绑定this
。
call()
、 apply()
或 bind()
可用于在函数内显式设置 this
的值。
- 当需要立即调用函数时,使用
call()
和apply()
。 bind()
返回一个稍后使用的新函数。
const obj = { name: 'Ben' };
function sayHello() {
console.log(`Hello, ${this.name}!`);
}
const sayHelloToBen = sayHello.bind(obj);
sayHelloToBen(); // Hello, Ben!
sayHello.call(obj); // Hello, Ben!
sayHello.apply(obj); // Hello, Ben!
在方法调用中的用法
如果函数是对象的方法,则引用该对象。
const person = {
name: 'Ben',
logThis: function() {
console.log(this);
}
}
person.logThis(); // { name: 'Ben', logThis: fn() }
常规函数调用中的用法(自由函数调用)
如果在全局上下文中调用函数,则 this
引用全局对象(在非严格模式下)或 undefined
(在严格模式下)。
对于浏览器来说,全局对象是 .
// Browser
function showThis() {
console.log(this);
}
showThis(); // Window { open: fn, alert: fn, ... }
当函数在全局上下文中声明时,它就成为 window
对象的属性。调用 window.showThis()
将产生相同的结果。这就是为什么它是隐式方法调用。 (参考上面这条规则)
如果应用多个规则,则将应用优先级较高的规则。
const obj1 = {
value: 1,
showThis: function() {
console.log(this);
},
};
const obj2 = { value: 2 };
obj1.showThis.call(obj2); // { value: 2 }
在上面的示例中,应用了两个规则:方法调用和显式绑定。由于显式绑定具有更高的优先级,因此它可以设置 this
的值。
箭头功能
箭头函数不遵循上述规则,因为它们没有自己的值。他们从父范围中选择值。
const person = {
name: 'Ben',
showThis: () => {
console.log(this);
},
showThisWrapped: function() {
const arrowFn = () => console.log(this);
arrowFn();
}
}
person.showThis(); // Window { open: fn, alert: fn, ... }
person.showThisWrapped(); // { name: 'Ben', showThis: fn, showThisWrapped: fn }
这就是为什么您应该避免对事件侦听器使用箭头函数。事件侦听器将 HTML 元素绑定到值,但如果处理程序是箭头函数,则这是不可能的。
document.querySelector('#cta').addEventListener('click', function(){
console.log(this); // HTMLButtonElement
})
document.querySelector('#cancel').addEventListener('click', () => {
console.log(this); // Window
})
概括
- 在函数构造函数(
new Person()
)中,this
将是新创建的对象实例。 - 如果使用
bind()
、call()
或apply()
显式绑定,函数内的this
将设置为提供的值。 - 在方法内部,
this
设置为该方法所属的对象。 - 在自由函数调用中,
this
指向全局对象(非严格模式)或undefined
(严格模式)。 - 如果适用多个规则,则首先规定的规则 (1-4) 将适用。
- 箭头函数没有自己的
this
。它的值是从父范围中选取的。