27

在解决另一个问题时,我创建了这个小提琴:

http://jsfiddle.net/tr2by/

function foo() {
    // console.log(_.isBoolean(this));
    console.log(this === true);
}

foo.call(true); // object:[object Boolean]
foo.apply(true); // object:[object Boolean]

这是自动装箱的一个例子吗?

从值类型到引用类型。

这是一个维基百科定义。

4

3 回答 3

53

首先,我假设您正在谈论将原始值自动转换为对象。这发生在 JavaScript 中的两种情况下:

  1. 当您将原始值作为this值传递给.callor.apply时(虽然不是在严格模式下)。
  2. 当您尝试访问原始值的“属性”时,例如"foo bar".split().

在第一种情况下,转换是永久性的,即this确实会引用一个对象,在第二种情况下,转换仅在评估期间在内部发生

如果您对转换的细节不感兴趣,您可以忽略其余的答案。


1.原始价值为this

当一个函数被执行并且它的this值不是一个对象时,它被转换为一个,至少在非严格模式下是这样。这在 ECMAScript 5.1 文档中的§10.4.3 Entering Function Code [spec]中有描述:

F当控制进入函数对象、提供的调用者thisArg和提供的调用者中包含的函数代码的执行上下文时,将执行以下步骤argumentsList

  1. 如果功能码是严格码,设置ThisBindingthisArg.
  2. 否则,如果thisArgnullundefined,则将 设置ThisBinding为全局对象。
  3. 否则,如果Type(thisArg)不是Object,则设置ThisBindingToObject(thisArg)。
    [...]

ToObject 正如您在第三步中看到的,通过调用[spec]将值转换为对象。

2. 物业准入

当您尝试访问属性时会发生类似的事情(§11.2.1 属性访问器[spec])。这里引用的部分解释了如何foo[bar]评估表达式,即如何评估使用括号表示法的属性访问。我们感兴趣的部分也适用于点符号。

生产MemberExpression : MemberExpression [ Expression ]评估如下:

  1. baseReference是评估的结果MemberExpression
  2. 让。baseValue_ [...] GetValue(baseReference)

   8. 返回一个类型的值,Referencebase值为baseValue,其引用名称为propertyNameString,其strict模式标志为strict

重要的一步是最后一步:无论MemberExpression评估什么,都将其转换为Reference [spec]类型的值。这是仅在规范中使用的数据类型,包含有关如何从引用中检索实际值的附加信息(不要与实际 JavaScript 代码中的对象引用混淆!)。

要从此类引用中获取“真实”值/结果,调用内部函数GetValue(V)(第 8.7.1 节)[规范](就像在上述算法的第 2 步中一样),其中说:

以下[[Get]]内部方法由GetValuewhen使用,V它是具有原始基值的属性引用。它被称为 usingbase作为其this值,并以属性P作为其参数。采取以下步骤:

  1. 让。O_ [...]ToObject(base)

例子:

假设我们有表达式

var foo = "BAR".toLowerCase();

这是一个赋值表达式,计算如下:

生产AssignmentExpression : LeftHandSideExpression = AssignmentExpression评估如下:

  1. lref是评估的结果LeftHandSideExpression
  2. rref是评估的结果AssignmentExpression
  3. 让。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并返回方法的结果。

于 2013-06-20T14:57:30.913 回答
5

Javascript 将提供给非严格模式的this参数装箱。来自MDNcallapply

如果方法是非严格模式代码中的函数,nullundefined被替换为全局对象,原始值将被装箱。

于 2013-06-20T14:55:02.000 回答
0

其他答案提供了有关何时发生自动装箱的详细信息,但还有一些需要记住的事情:

  • 使用运算符时不会发生自动装箱,如果接收到的值不是对象in,则会抛出 a 。TypeError一个简单的解决方案是手动将对象装箱Object(value)

  • 使用允许迭代字符串for...of的扩展语法进行迭代时会发生某种形式的自动装箱。[...value]

于 2018-11-02T22:21:11.443 回答