在解决另一个问题时,我创建了这个小提琴:
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值传递给.callor.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 属性访问器[spec])。这里引用的部分解释了如何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 节)[规范](就像在上述算法的第 2 步中一样),其中说:
以下
[[Get]]内部方法由GetValuewhen使用,V它是具有原始基值的属性引用。它被称为 usingbase作为其this值,并以属性P作为其参数。采取以下步骤:
- 让。
O_ [...]ToObject(base)
例子:
假设我们有表达式
var foo = "BAR".toLowerCase();
这是一个赋值表达式,计算如下:
生产
AssignmentExpression : LeftHandSideExpression = AssignmentExpression评估如下:
- 让
lref是评估的结果LeftHandSideExpression。- 让
rref是评估的结果AssignmentExpression。- 让。
rval_ [...]GetValue(rref)
步骤 1:评估左侧,即标识符foo。标识符如何准确解析对此并不重要。
步骤 2:评估右手边,即"BAR".toLowerCase()。该评估的内部结果将是一个参考值,类似于:
REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}
并存储在rref.
第三步:GetValue(rref)被调用。引用的base是 value "BAR"。由于这是一个原始值,ToObject将被调用以将其转换为临时 String对象。此外,引用实际上是一个属性访问,所以GetValue最终会调用对象toLowerCase上的方法String并返回方法的结果。
Javascript 将提供给非严格模式的this参数装箱。来自MDN:callapply
如果方法是非严格模式代码中的函数,
null将undefined被替换为全局对象,原始值将被装箱。
其他答案提供了有关何时发生自动装箱的详细信息,但还有一些需要记住的事情:
使用运算符时不会发生自动装箱,如果接收到的值不是对象in,则会抛出 a 。TypeError一个简单的解决方案是手动将对象装箱Object(value)。
使用允许迭代字符串for...of的扩展语法进行迭代时会发生某种形式的自动装箱。[...value]