"this" 关键字如何与 JavaScript 中的对象一起使用?
How does the "this" keyword work with objects in JavaScript?
由于我试图掌握 JavaScript 中可迭代对象的概念,我使用以下代码构建了一个:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}
Symbol.iterator
方法 returns 包含一个方法 (next
) 和两个属性(current
和 from
)的对象。此对象内的属性等于对象内的属性 range
.
因为 current
等于 this.from
而 last
等于 this.to
,我假设我可以直接从内部使用 this.from
和 this.to
方法 next
如下:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
next() {
if (this.from <= this.to) {
return { done: false, value: this.from++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}
但是,这样做会阻止迭代开始。观察到这一点后,我有两个问题:
为什么可以属性current
和last
使用关键字this
并让它引用对象range
而方法 next
不能? current
、last
和 next()
都是 相同的 对象的一部分,由 Symbol.iterator
.[=42= 返回]
此外,鉴于 Symbol.iterator()
returns 一个 单独的 对象, this
关键字不应该在那对象指的是那个对象本身?换句话说,属性 current
和 last
不应该 能够使用关键字 [=28= 从 range
访问属性]? range
不是一个单独的对象吗?
这 众所周知是一件棘手的事情。如此之多,以至于凯尔·辛普森 (Kyle Simpson) 几乎用整本书来讨论这个主题 (You Don't Know JS: this & Object Prototypes)。但是,在您的示例中,答案很简单 - 在第二个函数中,this 在 next()
函数中,因此解析为此函数。
为了检查 this 的范围,我正在使用 Chrome 的调试工具。如果您在右行暂停,它会告诉您 this 解析为什么。
关键字this
很复杂。当有更好的选择时避免使用它是明智的,通常会有,因为它有很多问题。
除此之外,答案如下:this
指的是 激活对象 (有时称为 上下文对象 ) 它的包含函数被调用。
激活对象是什么?它是调用函数时附加到的对象。 console.log()
的激活对象是 console
.
然而...
const x = {
log : console.log
};
x.log();
...这里x.log()
和console.log()
完全一样,只是激活对象是x
而不是console
.
看起来很简单,对吧?是的,有点。但还有更多事情需要了解。
- 有一个默认的上下文对象,当调用一个函数而不附加到一个对象时使用。它是全局对象,在浏览器中称为
window
,在Node.js中称为global
。
- 如果脚本是 strict mode 中的 运行,则没有默认上下文对象,如果未使用上下文
显式调用,它将是 undefined
- Arrow functions 使用词法范围,它们的
this
值根本不是通常的上下文对象——它是箭头函数定义的任何地方的父函数的上下文对象
现在让我们将上面的内容应用到您的代码中。最重要的是,如果在上下文为 range
对象的情况下调用您的 next()
方法,它就会起作用。问题是,在引擎盖下,引擎基本上是这样做的...
const returnedObject = range[Symbol.iterator]();
returnedObject.next();
... 所以 next
是以 returnedObject
作为上下文调用的,而不是 range
。但是返回对象 的函数是 以 range
作为其上下文调用的。因此,this
每个地方都不一样。
您实际上可以通过使用箭头函数而不是 shorthand 方法非常轻松地解决您的问题。
这会起作用:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
next : () => {
if (this.from <= this.to) {
return { done: false, value: this.from++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}
由于我试图掌握 JavaScript 中可迭代对象的概念,我使用以下代码构建了一个:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}
Symbol.iterator
方法 returns 包含一个方法 (next
) 和两个属性(current
和 from
)的对象。此对象内的属性等于对象内的属性 range
.
因为 current
等于 this.from
而 last
等于 this.to
,我假设我可以直接从内部使用 this.from
和 this.to
方法 next
如下:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
next() {
if (this.from <= this.to) {
return { done: false, value: this.from++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}
但是,这样做会阻止迭代开始。观察到这一点后,我有两个问题:
为什么可以属性
current
和last
使用关键字this
并让它引用对象range
而方法next
不能?current
、last
和next()
都是 相同的 对象的一部分,由Symbol.iterator
.[=42= 返回]此外,鉴于
Symbol.iterator()
returns 一个 单独的 对象,this
关键字不应该在那对象指的是那个对象本身?换句话说,属性current
和last
不应该 能够使用关键字 [=28= 从range
访问属性]?range
不是一个单独的对象吗?
这 众所周知是一件棘手的事情。如此之多,以至于凯尔·辛普森 (Kyle Simpson) 几乎用整本书来讨论这个主题 (You Don't Know JS: this & Object Prototypes)。但是,在您的示例中,答案很简单 - 在第二个函数中,this 在 next()
函数中,因此解析为此函数。
为了检查 this 的范围,我正在使用 Chrome 的调试工具。如果您在右行暂停,它会告诉您 this 解析为什么。
关键字this
很复杂。当有更好的选择时避免使用它是明智的,通常会有,因为它有很多问题。
除此之外,答案如下:this
指的是 激活对象 (有时称为 上下文对象 ) 它的包含函数被调用。
激活对象是什么?它是调用函数时附加到的对象。 console.log()
的激活对象是 console
.
然而...
const x = {
log : console.log
};
x.log();
...这里x.log()
和console.log()
完全一样,只是激活对象是x
而不是console
.
看起来很简单,对吧?是的,有点。但还有更多事情需要了解。
- 有一个默认的上下文对象,当调用一个函数而不附加到一个对象时使用。它是全局对象,在浏览器中称为
window
,在Node.js中称为global
。 - 如果脚本是 strict mode 中的 运行,则没有默认上下文对象,如果未使用上下文 显式调用,它将是
- Arrow functions 使用词法范围,它们的
this
值根本不是通常的上下文对象——它是箭头函数定义的任何地方的父函数的上下文对象
undefined
现在让我们将上面的内容应用到您的代码中。最重要的是,如果在上下文为 range
对象的情况下调用您的 next()
方法,它就会起作用。问题是,在引擎盖下,引擎基本上是这样做的...
const returnedObject = range[Symbol.iterator]();
returnedObject.next();
... 所以 next
是以 returnedObject
作为上下文调用的,而不是 range
。但是返回对象 的函数是 以 range
作为其上下文调用的。因此,this
每个地方都不一样。
您实际上可以通过使用箭头函数而不是 shorthand 方法非常轻松地解决您的问题。
这会起作用:
let range = {
from: 0,
to: 5
};
range[Symbol.iterator] = function() {
return {
next : () => {
if (this.from <= this.to) {
return { done: false, value: this.from++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
console.log(num);
}