理解 JavaScript 中的“this”
如果理解不正确,JavaScript 中的关键字经常this
会让人感到困惑。本文将this
通过一些代码示例向您展示关键字的工作原理,以及如何在 JavaScript 的不同上下文中赋值。在不同的场景下,this
关键字的值可能会发生变化:
- `this` in a global context, function invocation
- `this` in an object constructor
- `this` in an object method.
- `this` with arrow function (=>)
在跳到示例之前,我们先来看一下上下文,那么它在 JavaScript 中是什么呢? JavaScript 中的上下文始终是在代码执行过程中确定的值this
。为了更清楚地理解,我们现在通过代码示例来了解它在每种情况下是如何工作的。
console.log("What is 'this' value?", this) // Window
function simpleFunction () {
console.log("What is the value of this inside function?", this) // Window
}
simpleFunction()
从代码示例 1this
可以看出,全局对象是由执行上下文决定的,其中浏览器是全局对象(window)。同样,在函数内部调用函数时,this
该函数引用的也是全局对象。但是this
在构造函数内部,引用的又是什么呢?我们在下面的代码示例 2 中看到了这一点。
function Person(name, lastName) {
this.name = name;
this.lastName = lastName;
this.displayName = function() {
console.log(`Your name ${this.name} and lastName
${this.lastName}`)
}
}
let person = new Person('George', 'Superman')
person.displayName() // George Superman
从上面的代码中我们看到,我们创建了一个构造函数Person,然后调用了一个新的实例对象george。this
在这种情况下,value 指的是新创建的对象。
let greetings = {
word: 'Hello',
printGreeting: function(){
console.log("What 'this' refers to inside object method? ",
this.word) // "this" in object refers to the object itself- greetings
}
}
greetings.printGreeting()
从上面的代码示例 3 中,我们创建了一个具有属性和方法printGreeting 的对象。我们在方法内部调用属性名称this
,其值指向对象本身。
我们从上面的代码示例中看到,this
函数内部的值引用全局对象,对象方法内部的引用对象本身,但是如果我们想在另一个函数和引用中调用对象方法this
,那么在这种情况下,的值是什么呢this
?让我们看看代码示例 4,我们将在严格模式下运行它,如下所示
"use strict"
let person = {
firstName: 'George',
}
function printName(greeting) {
console.log(greeting + this.firstName)
}
printName('hello') // Uncaught TypeError: Cannot read property 'firstName' of undefined
运行代码后,我们发现出现了错误,因为 JavaScript 解释器无法理解对象属性this.firstName,因为this
函数内部的值是在执行上下文中设置的。但是,如何解决这个问题呢?JavaScript 函数是一种特殊类型的对象,它包含方法call()、apply()和bind()。
call()、apply() 和 bind()
所有函数都会继承这些方法,以便在任何所需的上下文中获取值this
。这些函数方法之间的区别在于:call()方法需要以逗号分隔的参数;apply() 方法以数组列表的形式传入,并且会立即执行;而 bind() 方法则可以稍后在任何所需的上下文中执行。下面的代码示例 5 展示了如何使用这些方法并this
在任何所需的上下文中设置值。
let person = {
firstName: 'George',
}
function printName(greeting) {
console.log(greeting + this.firstName);
}
printName.call(person, 'Hello') // Hello George
printName.apply(person, ['Hello there']) // Hello there George
let executeLater = printName.bind(person)
executeLater() // George
this
使用箭头函数 =>
ECMAScript 2015(ES6)引入了箭头函数,使其成为 JavaScript 领域的一项新功能。使用箭头函数有很多好处,它简化了函数语法,无需绑定this
。使用箭头函数时,函数this
在封闭上下文中具有词法界限。让我们通过代码示例来直观地了解这一点。
let greetings = {
word: 'Hello',
printGreeting(){
console.log(this.word) // Hello
})
}
}
回到前面的代码示例 2,我们看到this
inside object 指的是对象本身,但如果我们需要问候语在 1 秒后显示,该怎么办?为了获得所需的结果,我们需要修改代码,如下所示
let greetings = {
word: 'Hello',
printGreeting(){
window.setTimeout(function () {
console.log(this.word)
}, 1000) // we can set bind(this)
}
}
greetings.printGreeting() // undefined
我们看到,执行printGreeting()方法后,结果为 undefined,因为setTimout()函数调用将this
上下文设置为全局对象。然而,为了达到这个效果,我们可以使用前面提到的bind()方法,或者在setTimeout()函数之前创建一个闭包,并设置self=this 的值。不过,我们不需要这样做,因为我们可以使用箭头函数来实现所需的结果。
let greetings = {
word: 'Hello',
printGreeting(){
window.setTimeout(() => {
console.log(this.word)
}, 1000)
}
}
greetings.printGreeting() // Hello
现在,控制台上的结果将是问候语hello,因为使用箭头函数“ this ”绑定到封闭上下文,从而绑定到我们的“ greetings ”对象。
就是这样! :)
希望您觉得这篇文章有趣,并能帮助您理解this
JavaScript 及其在不同环境中的价值。