在 JS 中,为什么我可以使用像 toFixed() 这样的函数,它驻留在原始类型的 Number 包装器对象的原型中?

问题描述

在 JavaScript 中,原始类型(数字、字符串等)不是对象。因此,它们没有 [[prototype]] 因此不能使用某些对象的 [[prototype]] 中可用的方法

而 Number、String 是包装对象,可用于通过 new 关键字创建变量,我们可以在这些变量上使用 Number 对象原型中可用的方法(使用 new关键字)。

但在给定的代码中,我创建了一个原始类型变量,并且能够使用诸如 toFixed() 之类的方法,它驻留在 Number 对象中。

这让我很困惑。请详细说明这一点。

let a = 6.678; //primitive type

a= a.toFixed(1); // toFixed() resides in prototype of Number Object

console.log(a); // 6.7

解决方法

这与称为“自动装箱”的概念有关,Javascript 看到您正在尝试访问原始类型的属性,因此在运行时的一小段时间内,它会将原始值转换为其相应的包装对象并继续进行属性调用,然后在大多数情况下将值转换回原始类型。

let a = 6.678; //primitive type

a= a.toFixed(1); // JS converts a to "Number Object" and then the function is called

console.log(a); // 6.7

这是一个很好的答案Does javascript autobox?

,

这就是 JavaScript 引擎或多或少的工作方式。您是正确的,您分配给 a 的变量是 Number 类型的原始值,但是当您访问此原始值的方法时,JS 将创建一个特殊的包装对象(它将为每个原始值执行此操作)类型,即字符串)并允许它访问这些方法。

在您访问该方法后,该值将不再是一个对象。

您可以在此处阅读更多相关信息: https://javascript.info/primitives-methods#a-primitive-as-an-object

@ashu 在下面的回答中包含了我实际上并不知道的技术术语 - 所以 TIL!显然,这就是所谓的“自动装箱”!

,

由于 thisNumberValue 抽象操作,我们能够执行 toFixed() 操作,它检查 Type(value) 是 Number 返回值,否则如果 Type(value) 是 Object 并且 value 有 [[NumberData]]内部插槽,然后让 n 为值并分配 Type[n] 为 Number。返回值,否则抛出 TypeError 异常。

根据 ECMAScript® 2020 Language Specification

Number.prototype.toFixed (fractionDigits)

toFixed 返回一个包含此 Number 值的字符串,以十进制定点表示法表示,小数点后带有 fractionDigits 位。如果fractionDigits 未定义,则假定为0。

执行 toFixed() 操作时执行以下步骤:

  1. 设 x 为 ? thisNumberValue(this value)

注意 抽象操作 thisNumberValue(value) 执行以下步骤:

  • 如果 Type(value) 是数字,则返回值。

  • 如果 Type(value) 是 Object 并且 value 有一个 [[NumberData]] 内部 插槽,然后

    • 设 n 为值。[[NumberData]]。
    • 断言:Type(n) 是数字。
    • 返回 n。
  • 抛出 TypeError 异常。

  1. 让 f 是? ToInteger(fractionDigits)

    注意 抽象操作 ToInteger 将参数转换为整数值。此抽象操作的功能如下:
  • 让数字是? ToNumber(argument)。 (注意 ToNumber 也是一个抽象操作)
  • 如果数字为 NaN,则返回 +0。
  • 如果数字是 +0、-0、+∞ 或 -∞,则返回数字。
  • 返回数值 与数字同号,大小为 floor(abs(number)).
  1. 断言:如果 fractionDigits 未定义,则 f 为 0。