JavaScrpt this 关键词
在本教程,您将了解 JavaScript this 关键词并在各种上下文中清楚地理解它
在本教程中,您将了解 JavaScript this
关键词并在各种上下文中清楚地理解它。
如果您一直使用其他编程语言,例如 Java、C#或PHP,那么您已经熟悉 this
关键词。在这些语言中, this
关键词表示类的当前实例。而且它仅在 Class 内使用。
JavaScript 也有 this
关键词。但是,JavaScript 的 this
关键词与其他编程语言的行为不同。
在 JavaScript ,您可以在全局和函数上下文中使用 this
关键词。此外,this
关键字的行为在严格模式和非严格模式之间变化。
this 关键词是什么
通常,this 引用函数是其属性的对象。换句话说,this 引用当前正在调用函数的对象。
假设您有一个名为 counter
的对象,它有一个方法 next()
。当您调用 next()
方法时,您可以访问 this
对象。
let counter = {
count: 0,
next: function () {
return ++this.count;
},
};
counter.next();
在 next()
函数内部 ,this
引用 counter
对象。
counter.next();
next()
一个函数,它是 counter
对象的一个属性。因此,在 next()
函数内部,this
引用 counter
对象。
全局上下文
在全局上下文中,this
引用全局对象,它是 Web 浏览器的 window
对象或 Node.JS 的 global
对象。
这种行为在严格和非严格模式下都是一致的。这是 Web 浏览器的输出:
console.log(this === window); // true
如果您将属性分配给 this
全局上下文中的对象,JavaScript 会将属性添加到全局对象,如以下示例所示:
this.color= 'Red';
console.log(window.color); // 'Red'
函数上下文
在 JavaScript ,您可以通过以下方式调用函数:
- 函数调用
- 方法调用
- 构造函数调用
- 间接调用
每个函数调用都定义了自己的上下文。因此,this
行为会有所不同。
简单的函数调用
在非严格模式,函数调用时 this
引用全局对象,例如以下示例:
function show() {
console.log(this === window); // true
}
show();
当您调用 show()
函数时,this
引用全局对象,这是在网络浏览器的 window
对象和Node.JS 的 global
。
你也可已使用以下方式调用 show()
函数:
window.show();
在严格模式下,JavaScript 将函数内部的 this
设置为 undefined
. 例如:
"use strict";
function show() {
console.log(this === undefined);
}
show();
要启用严格模式,请在 JavaScript 文件开头使用指令 "use strict"
。如果只想将严格模式应用于指定函数,则将其放在函数体的顶部。
请注意,严格模式从 ECMAScript 5.1 起可用。strict
模式适用于函数和嵌套函数。例如:
function show() {
"use strict";
console.log(this === undefined); // true
function display() {
console.log(this === undefined); // true
}
display();
}
show();
输出:
true
true
在 display()
函数内部中,this
的也设置为 undefined
,如控制台所示。
方法调用
当您调用对象的方法时,JavaScript 设置 this
为拥有方法的对象。例如下面的 car
对象:
let car = {
brand: 'Honda',
getBrand: function () {
return this.brand;
}
}
console.log(car.getBrand()); // Honda
在这个例子中, this
对象在 getBrand()
方法引用 car
对象。由于方法是作为对象属性的值,因此您可以将其存储在变量。
let brand = car.getBrand;
然后通过变量调用方法
console.log(brand()); // undefined
你得到是 undefined
而不是 "Honda"
因为当你调用一个方法而不指定它的对象时,JavaScript 在非严格模式下将 this 的值设置为全局对象,在严格模式下将 this
设置为undefined
。
要解决此问题,您可以使用 Function.prototype
对象的 bind()
方法。bind()
方法创建一个新函数,可以将 this
设置为指定的值。
在下面例中,当您调用 brand()
方法时,this
关键字将绑定到 car
对象。例如:
let brand = car.getBrand.bind(car);
console.log(brand()); // Honda
在下面示例中,bind()
方法将 this
设置为 bike
对象,因此,您会在控制台看到 bike
对象的 brand
属性值 Harley Davidson 。
let car = {
brand: 'Honda',
getBrand: function () {
return this.brand;
}
}
let bike = {
brand: 'Harley Davidson'
}
let brand = car.getBrand.bind(bike);
console.log(brand());
输出:
Harley Davidson
构造函数调用
当您使用 new
关键词创建函数对象的实例时,您将函数用作构造函数。
以下示例声明一个 Car
函数,然后将其作为构造函数调用:
function Car(brand) {
this.brand = brand;
}
Car.prototype.getBrand = function () {
return this.brand;
}
let car = new Car('Honda');
console.log(car.getBrand());
表达式 new Car('Honda')
是将 Car
函数作为构造函数调用。JavaScript 创建一个新对象并设置 this
为新创建的对象。
现在,您可以调用 Car()
作为函数或构造函数。如果省略 new
关键词如下:
var bmw = Car('BMW');
console.log(bmw.brand);
// => TypeError: Cannot read property 'brand' of undefined
由于在 Car()
函数内 this
的值设置为全局对象,因此 bmw.brand
返回 undefined
.
为确保 Car()
函数始终使用构造函数来调用 ,您可以在 Car()
函数的开头添加一个检查,如下所示:
function Car(brand) {
if (!(this instanceof Car)) {
throw Error('Must use the new operator to call the function');
}
this.brand = brand;
}
ES6 引入一个名为 new.target
的元属性 ,它允许您检测一个函数是使用简单方式调用还是作为构造函数被调用。
您可以修改 Car()
函数使用 new.target
元属性,如下所示:
function Car(brand) {
if (!new.target) {
throw Error('Must use the new operator to call the function');
}
this.brand = brand;
}
间接调用
在 JavaScript,函数是一等公民。换句话说,函数是对象,是 Function 原型的实例。
Function
原型有两个方法:call()
和 apply()
。这些方法允许您在调用函数时设置 this
的值。例如:
function getBrand(prefix) {
console.log(prefix + this.brand);
}
let honda = {
brand: 'Honda'
};
let audi = {
brand: 'Audi'
};
getBrand.call(honda, "It's a ");
getBrand.call(audi, "It's an ");
输出:
It's a Honda
It's an Audi
在这个例子中,我们使用 getBrand()
函数原型对象的 call()
方法间接调用 getBrand
函数。
我们将 object 作为方法的第一个参数传递, 因此,我们在每次调用中都获得了相应的品牌。call()getBrandhondaaudicall()
我们分别将 honda
和 audi
对象作为 call 方法第一个参数传递,因此我们在每次调用中都能获取到正确品牌名称。
apply()
方法与 call()
方法类似,只是它的第二个参数是一个数组,数组的元素将作为 getBrand 函数的参数。
getBrand.apply(honda, ["It's a "]); // "It's a Honda"
getBrand.apply(audi, ["It's an "]); // "It's a Audi"
箭头函数
ES6 引入了一个新概念,叫做箭头函数。在箭头函数,JavaScript 按照词法设置 this
。
这意味着箭头函数不会创建自己的执行上下文,this
的值将会被设置为定义箭头函数的外部对象。请参阅以下示例:
let getThis = () => this;
console.log(getThis() === window); // true
在此示例中,this
值设置为全局对象,即在 Web 浏览器的 window
。
由于箭头函数不会创建自己的执行上下文,因此使用箭头函数定义方法会导致问题。例如:
function Car() {
this.speed = 120;
}
Car.prototype.getSpeed = () => {
return this.speed;
};
var car = new Car();
console.log(car.getSpeed()); // 👉 undefined
在 getSpeed()
方法内部,this
值引用全局对象,而不是 Car
对象,但全局对象没有名为 speed 的属性。因此,getSpeed()
方法的 this.speed
是 undefined
。