David Flanagan 的 Definitive JavaScript 对对象和基元进行了区分。
他将原语定义为 Number、String、Boolean、Null 和 Undefined,标准也是如此。
但是,将原始对象定义为对象的子集(即称它们为原始对象)会更准确吗?
因为它们有自己的方法并且是复杂的实体。
实际问题
在定义 String、Boolean 和 Number 时,Primitive Object 会比 Object 更准确吗?
David Flanagan 的 Definitive JavaScript 对对象和基元进行了区分。
他将原语定义为 Number、String、Boolean、Null 和 Undefined,标准也是如此。
但是,将原始对象定义为对象的子集(即称它们为原始对象)会更准确吗?
因为它们有自己的方法并且是复杂的实体。
实际问题
在定义 String、Boolean 和 Number 时,Primitive Object 会比 Object 更准确吗?
对象和原语是不同的:
typeof 42 === "number"
typeof new Number(42) === "object"
new Number(42) !== 42
但是,在必要时,原语会自动被临时对象包装,这些临时对象可以自动转换回原语:
(42).toString() === "42"
new Number(42) == 42
new Number(42) + 1 === 43
尤其是在 Java 和 C# 编程语言的上下文中,这种行为称为自动装箱。由于包装对象具有一些令人困惑的特征,例如:
Boolean(new Boolean(false)) === true
最好避免有意将它们存储在变量中,而是尽可能使用原语。
这与语义无关,请看:
var threePrimitive = 3;
var threeObject = new Number(3);
threePrimitive.toFixed(2); // 3.00
threeObject.toFixed(2); // 3.00
threePrimitive.foo = true
threeObject.foo = true;
threePrimitive.foo; // undefined
threeObject.foo; // true
当您尝试对其调用方法时,基元被包装在对象中,但在初次使用后,该对象被丢弃。
至于规范中如何说明这一点,我不是 100% 确定,但这是我的想法(基于Bergi 在他的答案之一中留下的提示。第11.2.1 节指出应该评估访问器属性如下:
- 让 baseReference 成为评估 MemberExpression 的结果。
- 设 baseValue 为
GetValue
( baseReference )。(...)
然后在8.7.1中我们看到以下内容:
当V是具有原始基值的属性引用时,GetValue 使用以下 [[Get]] 内部方法。使用 base 作为其
this
值并以属性P作为其参数来调用它。采取以下步骤:
- 令 O 为 ToObject(base)。
- 令 desc 为使用属性名称 P 调用 O 的 [[GetProperty]] 内部方法的结果。
- 如果 desc 未定义,则返回未定义。
- 如果 IsDataDescriptor(desc) 为真,则返回 desc.[[Value]]。
- 否则, IsAccessorDescriptor(desc) 必须为真,所以,
- 让 getter 为 desc.[[Get]]。如果 getter 未定义,则返回未定义。
- 返回调用 getter 的 [[Call]] 内部方法的结果,提供 base 作为 this 值并且不提供任何参数。
注意 可能在步骤 1 中创建的对象在上述方法之外是不可访问的。实现可能会选择避免实际创建对象。使用此内部方法的这种实际属性访问可以产生可见效果的唯一情况是它调用访问器函数时。
在定义 String、Boolean 和 Number 时,Primitive Object 会比 Object 更准确吗?
请注意,我并不是说数字不是这里的对象,而是指出它看起来模棱两可。这是让 JavaScript 新手感到困惑的事情。
这种区别主要是学术上的,但有一种情况似乎模棱两可:文字表示原始对象,除非文字似乎表示数字。您不能将方法直接应用于文字 integer* 符号:
1.toString();
SyntaxError: identifier starts immediately after numeric literal
…但你可以应用 Numbers 的方法:
Number(1).toString();
'1'
…并且包含数字的名称是数字:
x = 4;
x.toString();
'4'
我认为这实际上是一个解析问题,但我真的不知道为什么解析器不能1
像判断“abc”是一个字符串那样容易地判断这是一个数字。我想这与.
符号的语义歧义有关。(是小数点还是方法运算符?)
*JavaScript 实际上没有整数。我只是指一个完全由 组成的符号[0-9]+
。