JavaScript:理解“this”关键字
'this'
是 JavaScript 中最重要的概念之一。它是基础的一部分,你越早掌握它,你的编程生涯就会越轻松 :)
通过阅读这篇文章,确保您理解“this”的用法。
首先,简单解释一下 5 岁儿童的情况:
在编程中,“this”的用法
'this'
和普通英语的用法类似。例如,当你说“我找到工作了!太棒了!”时,我们知道“this”指的是你找到工作了。换句话说,“this”为第二句话提供了上下文。
--5岁
因此,要理解'this'
,您需要知道什么是上下文。
背景解释
上下文与对象相关。它指的是方法或属性所属的对象。您的代码开始在全局上下文中运行,在浏览器中,该上下文称为window
(在 Node 中,全局对象称为global
)。请看以下示例:
var name ='Beyonce'
console.log(this.name) // Beyonce
console.log(window.name) // Beyonce
示例中的'this'
equals 是window
因为我在浏览器上运行了它,其中全局对象是窗口。所以,window.name ==="Ash" 。到目前为止,上下文是窗口。好的。
现在,上下文在代码执行过程中会发生变化。每当调用对象的方法时,'this'
都会设置为调用该方法的对象。
请参见下面的示例。第 4 行和第 10 行相同,但它们根据 的值记录不同的结果'this'
。
var name = 'Beyonce'
function sayMyName(){
console.log(`Your name is ${this.name}.`) // 'this' is window
}
var heisenberg = {
name: 'Heisenberg',
sayMyName: function () {
console.log(`Your name is ${this.name}.`) // 'this' is heisenberg
}
}
sayMyName() // Your name is Beyonce.
heisenberg.sayMyName() // Your name is Heisenberg.
上面的代码运行良好,但是我们重复了第 4 行,这并不酷(记住:DRY 不要重复自己)。
有一种方法可以console.log()
只写入一次并重复使用。为此,我们使用函数bind
。
绑定的“this”
Bind
将给定的'this'
对象应用于调用它的函数。要绑定到函数的对象将作为参数传递给 bind。
参见示例:
function sayMyName(){
console.log(`Your name is ${this.name}.`)
}
var beyonce = {
name: 'Beyonce',
}
var heisenberg = {
name: 'Heisenberg',
}
let sayBeyonce= sayMyName.bind(beyonce)
let sayHeisenberg= sayMyName.bind(heisenberg)
sayBeyonce() // Your name is Beyonce.
sayHeisenberg() // Your name is Heisenberg.
太棒了!现在,假设我们不想创建新函数来读出每个人的名字。我们只想使用 sayMyName() 。
我们可以使用call
函数和通用的 person 对象来实现这一点。
'this' 调用
与绑定类似,call
可用于将自定义值设置为'this'
。
参见示例:
var person = {
sayMyName: function(){ console.log(`Your name is ${this.name}.`)};
}
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Beyonce.
person.sayMyName.call(heisenberg); // Your name is Heisenberg.
箭头函数中的“this”
小心使用箭头函数🏹
当使用箭头函数时,它不会为 设定新值'this'
,而是从父作用域继承。
此示例与前一个示例相同,但使用箭头函数而不是普通函数。
控制台里输出了两次“Ash”。很奇怪吧?
var name = 'Ash';
var person = {
sayMyName: () => console.log(`Your name is ${this.name}.`)
};
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Ash.
person.sayMyName.call(heisenberg); // Your name is Ash.
即使你使用 call/bind 也不起作用。它仍然会打印“Ash”。为什么?
常规函数与箭头函数的“this”
常规函数将其自己的'this'
对象设置给调用者。
但是箭头函数却不会。它们继承'this'
自之前的上下文,也就是它所在的作用域。在本例中,就是从 window 继承。这被称为“词法作用域”。
所以,当我们使用箭头函数时,'this'
它与函数的调用者没有任何关系。它仍然等于window
并且保持这种状态,结果输出“Ash”。
如果我们用常规函数包装箭头函数会怎么样?
调用常规函数并将其设置'this'
为调用者。
箭头函数在常规函数内部被调用。箭头函数中的 this 值继承了外部(常规)函数的 this 值。所以它成功了!
var name = 'Ash';
var person = {
sayMyName: function () {
const arrowFunction = () => console.log(`Your name is ${this.name}.`);
arrowFunction();
},
};
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Beyonce.
person.sayMyName.call(heisenberg); // Your name is Heisenberg.
酷!所以使用箭头函数不好?完全不是。有很多用例需要你从周围的上下文中继承“this”。在这种情况下,箭头函数非常有用。
箭头函数中 this 的有用场景
我们来看一个例子。这里,我们想使用一个名称数组,每 2 秒记录一个不同的名称。运行此代码时,会收到错误:[Uncaught TypeError: Cannot read property 'forEach' of undefined]。
var people = {
names: ['Ash', 'Beyonce', 'Heisenberg'],
sayNames: function () {
// log each name after 1 second
setTimeout(function () {
console.log(this);
this.names.forEach(function (name) {
console.log('your name is' + name);
});
}, 2000);
},
};
people.sayNames();
为什么?
调用 sayNames 时,它会将“this”设置为 people 对象。但是调用 setTimeout 时,它会将“this”设置为 window 对象。window 没有names
属性。该如何解决这个问题?
你猜对了!我们使用了一个箭头函数,它会从外部上下文继承 this。换句话说,它会'this'
从 sayNames 上下文继承。
var people = {
names: ['Ash', 'Beyonce', 'Heisenberg'],
sayNames: function () {
console.log(this);
// log each name after 1 second
setTimeout( ()=> {
console.log(this);
this.names.forEach(function (name) {
console.log('your name is ' + name);
});
}, 2000);
},
};
people.sayNames();
关于我,让我们联系吧!👋👩💻
感谢阅读!我是一个充满热情的学习者,喜欢分享我的知识。我在这里 免费直播编程👉,并在我的推特上分享编程技巧。如果你感兴趣,欢迎来我这里聊天室跟我打个招呼😁
鏂囩珷鏉ユ簮锛�https://dev.to/simonpaix/javascript-understand-this-keyword-55j