在解决另一个问题时,我创建了这个小提琴:
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 属性访问器[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]]
内部方法由GetValue
when使用,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:call
apply
如果方法是非严格模式代码中的函数,
null
将undefined
被替换为全局对象,原始值将被装箱。
其他答案提供了有关何时发生自动装箱的详细信息,但还有一些需要记住的事情:
使用运算符时不会发生自动装箱,如果接收到的值不是对象in
,则会抛出 a 。TypeError
一个简单的解决方案是手动将对象装箱Object(value)
。
使用允许迭代字符串for...of
的扩展语法进行迭代时会发生某种形式的自动装箱。[...value]