javascript 自动装箱吗?

IT技术 javascript
2021-01-17 08:39:50

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

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]

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

从值类型到引用类型。

这是维基百科的定义。

3个回答

首先,我假设您正在谈论原始值到对象的自动转换。这在 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 属性访问器[规范])。此处引用的部分解释了表达式foo[bar]的计算方式,即如何计算使用括号表示法的属性访问。我们感兴趣的部分也适用于点表示法。

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

  1. baseReference成为评估的结果MemberExpression
  2. 我们baseValueGetValue(baseReference)
    [...]

   8. 返回一个类型Reference值,base值为baseValue,引用名称为propertyNameStringstrict模式标志为strict

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

为了从这样的引用中获得“真实”值/结果,内部函数GetValue(V)(第 8.7.1 节)[spec]被调用(就像在上述算法的第 2 步中一样),它说:

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

  1. 我们OToObject(base)
    [...]

例子:

假设我们有表达式

var foo = "BAR".toLowerCase();

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

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

  1. lref成为评估的结果LeftHandSideExpression
  2. rref成为评估的结果AssignmentExpression
  3. 我们rvalGetValue(rref)
    [...]

第 1 步:评估左侧,即 identifier foo标识符的解析方式对此并不重要。
第 2 步:评估右侧,即"BAR".toLowerCase()评估内部结果将是一个参考值,类似于:

REFERENCE = {
    base: "BAR",
    propertyNameString: "toLowerCase",
    strict: false
}

并存储在rref.

第三步:GetValue(rref)被调用。base参考的是值"BAR"由于这是一个原始值,ToObject将被调用以将其转换为临时 String对象。此外,引用实际上是一个属性访问,因此GetValue最终会调用对象toLowerCase上的方法String并返回方法的结果。

...我猜在严格模式下,第 2 步是不同的,this设置为undefined,对吗?
2021-03-19 08:39:50
@Pointy:这是一个if ... else声明(很难看到,我知道)。当步骤 1 中的条件为真时,不执行步骤 2。
2021-03-22 08:39:50
- 在哪里ThisBindingthisArg定义......这甚至包括自动装箱
2021-03-24 08:39:50
你知道在严格模式下会发生什么吗?我想我可以自己测试一下,但是...
2021-03-26 08:39:50
@Ian 在严格模式下,我们this在第 1 步完成设置。这this是实际的原始值。
2021-04-03 08:39:50

Javascript 将this提供给callapply在非严格模式下参数装箱来自MDN

如果该方法是在非严格模式代码的功能,nullundefined将与全局对象来代替,而原始的值将被装箱。

@the_web_situation 我你可以这么说——这是一种无需编写代码来显式执行转换的情况下,即可获得原语的盒装版本。如果你想称之为“自动装箱”,我猜就去吧?
2021-03-25 08:39:50
@the_web_situation 这取决于您所说的“自动”是什么意思。
2021-04-06 08:39:50

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

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

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

for...of和传播语法都使用迭代协议,它访问Symbol.iterator可迭代对象上的方法 - 与任何其他值一样的属性访问。
2021-03-15 08:39:50