2023年 前端已死 拯救落魄前端面试圣经之js this篇
成功的秘诀在于每天都有所进步,即使只是一点点也可以。- 约翰·C·迪维尔比
大家好,我是siuuuuuuuuu。
在如今的互联网大环境下,每个人都岌岌可危。本着互联网行业天然的高波动性, 有可能你上午还在工位摸鱼,下午HR
已经给你单独开小灶,通知你提前毕业了。所以在当前的互联网环境,每天刷八股文变得很有必要, 因为你永远都会随时被毕业.
该圣经系列就是为各位广大的前端从业者准备,该圣经如同武林中绝世武学. 读完此文,融会贯通后, 拳打面试官,脚踢hr, offer拿到手软,不在话下。
废话不多说,接下来进入正题。
在 JavaScript 中,this 关键字用于引用当前函数执行上下文的对象。它指向的是当前函数被调用时正在执行的对象。
具体来说,this 指向取决于函数调用方式。当在函数中使用 this 时,其值取决于该函数的调用方式。以下是四种常见的调用方式及其 this 的指向:
- 函数作为对象的方法被调用
当函数作为对象的方法被调用时,this 指向该对象。
示例代码:
const person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
return this.firstName + " " + this.lastName;
}
}
console.log(person.fullName()); // "John Doe"
- 函数作为普通函数被调用
当函数作为普通函数被调用时,this 指向全局对象(在浏览器环境下指向 window 对象,在 Node.js 环境下指向 global 对象)。
示例代码:
function myFunction() {
console.log(this); // Window(在浏览器环境下)
}
myFunction();
- 使用 call 或 apply 方法调用函数
使用 call 或 apply 方法可以显式地将 this 绑定到一个特定的对象上。
示例代码:
const person1 = {
firstName: "John",
lastName : "Doe",
fullName : function() {
return this.firstName + " " + this.lastName;
}
}
const person2 = {
firstName: "Mary",
lastName: "Doe"
}
console.log(person1.fullName.call(person2)); // "Mary Doe"
- 使用构造函数调用函数
在使用构造函数创建新对象时,this 指向新创建的对象。
示例代码:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = function() {
return this.firstName + " " + this.lastName;
}
}
const person = new Person("John", "Doe");
console.log(person.fullName()); // "John Doe"
在 JavaScript 中,this 关键字用于引用当前函数执行上下文的对象。它指向的是当前函数被调用时正在执行的对象。
然而,在 JavaScript 中,this 的设计存在着一些缺陷。其中最常见的问题是 this 的指向不稳定,容易受到函数调用方式、箭头函数等因素的影响,导致开发人员难以理解和预测代码行为。下面我们对此进行详细介绍:
指向不稳定
当一个函数被调用时,this 的指向取决于函数的调用方式。如果函数作为对象的方法被调用, this 就指向该对象;如果函数被作为普通函数调用,this 就指向全局对象(在浏览器环境下指向 window 对象,在 Node.js 环境下指向 global 对象);而使用构造函数来创建新对象时,则 this 指向新创建的对象。
示例代码:
Copy Code
const person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
console.log(this.firstName + " " + this.lastName);
}
}
person.fullName(); // "John Doe"
function myFunction() {
console.log(this); // Window(在浏览器环境下)
}
myFunction();
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = function() {
console.log(this.firstName + " " + this.lastName);
}
}
const person = new Person("John", "Doe");
person.fullName(); // "John Doe"
指向对象继承链的顶部
另一个常见的问题是,this 有时会指向对象继承链的顶部(例如 Object.prototype)。这通常发生在尝试访问对象属性时。
示例代码:
Copy Code
const person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
console.log(this.firstName + " " + this.lastName);
}
}
const student = Object.create(person);
student.grade = "A";
student.fullName(); // TypeError: Cannot read property 'firstName' of undefined
在上面的代码中,我们创建了一个 person 对象,并将其作为原型链创建了 student 对象。调用 student.fullName() 时,会抛出 TypeError 异常,因为该方法中的 this 指向 student 对象本身,而该对象没有定义 firstName 和 lastName 属性。
应对方案
为了解决 this 的指向不稳定等问题,开发人员可以使用一些技术手段来规避这些风险。以下是一些可能的应对方案:
- 将 this 指定为固定值
通过使用 Function.prototype.bind()、Function.prototype.call() 或 Function.prototype.apply() 等方法,可以将函数中的 this 绑定到特定的值或对象上。
示例代码:
Copy Code
const person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
console.log(this.firstName + " " + this.lastName);
}
}
const myFunction = person.fullName.bind(person);
myFunction(); // "John Doe"
在这个示例中,我们使用 Function.prototype.bind() 将 person.fullName() 方法中的 this 指向 person 对象,并将其赋值给 myFunction 变量。调用 myFunction() 时,this 会指向 person 对象,输出 "John Doe"。
- 使用箭头函数
在箭头函数中,this 始终指向定义时所在的上下文环境,而不是调用时的上下文环境。因此,箭头函数可以避免 this 的指向不稳定问题。
示例代码:
Copy Code
const person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
const getFullName = () => {
console.log(this.firstName + " " + this.lastName);
}
getFullName();
}
}
person.fullName(); // "John Doe"
在这个示例中,getFullName() 函数是一个箭头函数,它继承了 person.fullName() 中的 this 值,并将其用于输出完整姓名。
总的来说,this 的设计确实存在一些缺陷,容易受到外部因素的干扰,导致代码难以预测和理解。但是,通过使用上述应对方案,以及仔细考虑函数的调用方式和执行上下文等因素,开发人员可以减少这些问题的影响。
转载自:https://juejin.cn/post/7241386428629549111