在处理另一个问题时,我创造了这个小提琴:
function foo() {
// console.log(_.isBoolean(this));
console.log(this === true);
}
foo.call(true); // object:[object Boolean]
foo.apply(true); // object:[object Boolean]
这是自动装箱的一个例子吗?
从值类型转到引用类型。
答案 0 :(得分:35)
首先,我假设您正在讨论将原始值自动转换为对象。在JavaScript中有两种情况:
this
值传递给.call
或.apply
时(尽管不是严格模式)。"foo bar".split()
。在第一种情况下,转换是永久性的,即this
确实将引用一个对象,在第二种情况下,转换仅在内部进行评估期间
如果您对转换的细节不感兴趣,可以忽略其余的答案。
<强> 1。原始值为this
当函数被执行且其this
值不是对象时,它将转换为1,至少在非严格模式下。这在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 Property Accessors [spec])时会发生类似情况。这里引用的部分解释了如何评估表达式foo[bar]
,即如何评估带括号表示法的属性访问。我们感兴趣的部分也适用于点符号。
生产
MemberExpression : MemberExpression [ Expression ]
的评估如下:
- 让
的结果baseReference
成为评估MemberExpression
。- 让
醇>baseValue
成为GetValue(baseReference)
[...]8.返回
Reference
值为base
且其引用名称为baseValue
且其propertyNameString
模式标志为{的strict
类型的值{1}}。
重要的一步是最后一步:无论strict
评估什么,它都会转换为Reference
[spec]类型的值。这是仅在规范中使用的数据类型,并包含有关如何从引用中检索实际值的其他信息(不要与实际JavaScript代码中的对象引用混淆!)。
要从这样的引用中获取“真实”值/结果,将调用内部函数GetValue(V)
(§8.7.1) [spec](就像上面算法中的步骤2一样),其中显示:
当
MemberExpression
是具有原始基值的属性引用时,[[Get]]
使用以下GetValue
内部方法。使用V
作为其base
值并使用属性this
作为其参数调用它。采取以下步骤:
- 让
醇>P
成为O
[...]
示例:强>
假设我们有表达式
ToObject(base)
这是一个赋值表达式,其计算方法如下:
生产
var foo = "BAR".toLowerCase();
的评估如下:
- 让
的结果AssignmentExpression : LeftHandSideExpression = AssignmentExpression
成为评估lref
。- 让
的结果LeftHandSideExpression
成为评估rref
。- 让
醇>AssignmentExpression
成为rval
[...]
步骤1:评估左侧,即标识符GetValue(rref)
。如何准确识别标识符并不重要。
步骤2:评估右侧,即foo
。该评估的内部结果将是一个参考值,类似于:
"BAR".toLowerCase()
并存储在REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}
。
第3步:调用rref
。引用的GetValue(rref)
是值base
。由于这是一个原始值,因此将调用"BAR"
将其转换为临时 ToObject
对象。此外,引用实际上是属性访问,因此String
最终将调用GetValue
对象上的方法toLowerCase
并返回方法的结果。
答案 1 :(得分:5)
Javascript将this
参数提供给call
和apply
非严格模式。来自MDN:
如果该方法是非严格模式代码中的函数,则
null
和undefined
将替换为全局对象,并且原始值将被加框。
答案 2 :(得分:0)
其他答案提供了有关自动装箱何时发生的详细信息,但是还有两点需要记住:
in
运算符时,不会发生自动装箱 ,如果接收到的值不是对象,该运算符将引发TypeError
。一种简单的解决方案是使用Object(value)
手动将对象装箱。
使用for...of
或扩展语法[...value]
进行迭代时,会发生某种形式的自动装箱。