在解决另一个问题时,我创建了这个小提琴:
function foo() {
// console.log(_.isBoolean(this));
console.log(this === true);
}
foo.call(true); // object:[object Boolean]
foo.apply(true); // object:[object Boolean]
这是自动装箱的一个例子吗?
从值类型到引用类型。
这是维基百科的定义。
在解决另一个问题时,我创建了这个小提琴:
function foo() {
// console.log(_.isBoolean(this));
console.log(this === true);
}
foo.call(true); // object:[object Boolean]
foo.apply(true); // object:[object Boolean]
这是自动装箱的一个例子吗?
从值类型到引用类型。
这是维基百科的定义。
首先,我假设您正在谈论原始值到对象的自动转换。这在 JavaScript 中有两种情况:
this
值传递给.call
or 时.apply
(尽管不是在严格模式下)。"foo bar".split()
.在第一种情况下,转换是永久性的,即this
确实会引用一个对象,在第二种情况下,转换仅在评估期间在内部发生
如果你对转换的细节不感兴趣,你可以忽略其余的答案。
1. 原始值作为 this
当一个函数被执行并且它的this
值不是一个对象时,它被转换为一个,至少在非严格模式下是这样。这在 ECMAScript 5.1 文档中的§10.4.3 Entering Function Code [spec]中有描述:
当控制进入包含在函数对象
F
、提供thisArg
的调用方和提供的调用方中的函数代码的执行上下文时,将执行以下步骤argumentsList
:
- 如果函数代码是严格代码,则设置
ThisBinding
为thisArg
。- 否则,如果
thisArg
是null
或undefined
,则将 设置ThisBinding
为全局对象。- 否则,如果
Type(thisArg)
不是Object
,则将其设置ThisBinding
为ToObject(thisArg
)。
[...]
正如您在第三步中看到的,通过调用ToObject
[spec]将值转换为对象。
2. 属性访问
当您尝试访问属性时会发生类似的事情(§11.2.1 属性访问器[规范])。此处引用的部分解释了表达式foo[bar]
的计算方式,即如何计算使用括号表示法的属性访问。我们感兴趣的部分也适用于点表示法。
生产
MemberExpression : MemberExpression [ Expression ]
评估如下:
- 让
baseReference
成为评估的结果MemberExpression
。- 我们
baseValue
是GetValue(baseReference)
。
[...]8. 返回一个类型
Reference
的值,其base
值为baseValue
,引用名称为propertyNameString
,strict
模式标志为strict
。
重要的一步是最后一步:无论求什么MemberExpression
值,都将其转换为Reference
[spec]类型的值。这是一种仅在规范中使用的数据类型,包含有关如何从引用中检索实际值的附加信息(不要与实际 JavaScript 代码中的对象引用混淆!)。
为了从这样的引用中获得“真实”值/结果,内部函数GetValue(V)
(第 8.7.1 节)[spec]被调用(就像在上述算法的第 2 步中一样),它说:
以下
[[Get]]
内部方法由GetValue
whenV
使用具有原始基值的属性引用。它被称为 usingbase
作为其this
值并以 propertyP
作为其参数。采取以下步骤:
- 我们
O
是ToObject(base)
。
[...]
例子:
假设我们有表达式
var foo = "BAR".toLowerCase();
这是一个赋值表达式,其计算方式如下:
生产
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
评估如下:
- 让
lref
成为评估的结果LeftHandSideExpression
。- 让
rref
成为评估的结果AssignmentExpression
。- 我们
rval
是GetValue(rref)
。
[...]
第 1 步:评估左侧,即 identifier foo
。标识符的解析方式对此并不重要。
第 2 步:评估右侧,即"BAR".toLowerCase()
。该评估的内部结果将是一个参考值,类似于:
REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}
并存储在rref
.
第三步:GetValue(rref)
被调用。该base
参考的是值"BAR"
。由于这是一个原始值,ToObject
将被调用以将其转换为临时 String
对象。此外,引用实际上是一个属性访问,因此GetValue
最终会调用对象toLowerCase
上的方法String
并返回方法的结果。
Javascript 将this
提供给call
和apply
在非严格模式下的参数装箱。来自MDN:
如果该方法是在非严格模式代码的功能,
null
和undefined
将与全局对象来代替,而原始的值将被装箱。
其他答案提供了有关何时发生自动装箱的详细信息,但还有几件事要记住:
使用运算符时不会发生自动装箱in
,TypeError
如果接收到的值不是对象,则抛出 a 。一个简单的解决方案是用 手动装箱对象Object(value)
。
某种形式的自动装箱在迭代使用for...of
或[...value]
允许迭代字符串的扩展语法时发生。