JavaScript对象和基元类型有什么区别?

时间:2014-02-21 11:25:38

标签: javascript

Stoyan Stefanov在其出色的“面向对象的JavaScript”一书中说:

  

任何不属于上面列出的五种基本类型之一的值都是一个对象。

有五种原始类型,他的意思是NumberStringBooleanUndefinedNull。但是在Google Chrome控制台中,数字似乎根本不是原始类型(与C基本类型(如int相比)。看起来原语号码有方法:

var a = 2.2;
console.log(a.toFixed()); // logs "2"

因此我假设我可以使用数字作为对象,所以我尝试为它分配一个属性:

var a = 2;
a.foo = 'bar';
console.log(a.foo); // logs undefined

我不明白这种行为。如果number有一个方法,它应该表现得像对象,不应该吗?它甚至有一个原型:

Number.prototype.foo = 'bar';
var a = 2;
console.log(a.foo); // logs 'bar'

那么这背后的魔法是什么? JavaScript如何处理对象与原始类型?我宁愿不使用 primitive 这个词,而是用简单对象替换它。正如我所看到的那些是无法用新属性扩展的对象,但它们是通过构造函数构造的,并且还具有可以像普通对象一样扩展的原型。

1 个答案:

答案 0 :(得分:10)

  

[...] 看起来像原始数字有方法

原语实际上并没有自己的属性。它被强制转换为一个对象,以便能够访问“它的”属性。强制对象在被调用的方法*之外是不可访问的(在严格模式下甚至在方法内)*。因此,引用的变量始终是原始的。

考虑这个简单的例子:

Number.prototype.myTypeInAMethod = function () {
   console.log (typeof this.valueOf ()) //"number" => The primitive is wrapped in an object. 
   return typeof this;
}

var num = 123;
typeof num; //number
num.myTypeInAMethod () //object

旁注:在ES5s严格模式下,this将是一个原语,类型将为数字

由于变量num是基元,因此您可以为其指定值。

num.foo = "bar";
num.foo //undefined

如果您通过其对象构造函数创建一个数字(或字符串),则其类型确实是一个对象。 通过添加属性进行快速检查表明它实际上可以被分配。

var objNum = new Number(123);
typeof objNum ; //"object"
objNum.foo = "bar";
objNum.foo //"bar"

  

那背后的魔力是什么? JavaScript如何处理对象与原始类型?

ES5 §8.7.1 GetValue

中描述了此过程

对象:

  • 如果Type(V)不是参考,请返回 V
  • 让base成为调用GetBase(V)
  • 的结果
  • 如果IsUnresolvableReference(V),则抛出 ReferenceError 异常。
  • 如果IsPropertyReference(V),那么
    • 如果HasPrimitiveBase(V) false ,则让获取成为 base 的[[Get]]内部方法,否则让 get 是下面定义的特殊[[Get]]内部方法。
    • 使用 base 作为 this 值返回调用 get 内部方法的结果,并为参数传递GetReferencedName(V)
  • 否则, base 必须是环境记录。
    • 返回调用 base GetBindingValue(参见10.2.1)具体方法的结果,将GetReferencedName(V)IsStrictReference(V)作为参数传递。

对于原语:

  

当V是属性引用 [1] 时,GetValue使用以下[[Get]]内部方法   原始基值。使用base作为其值并使用属性P作为其参数调用它。   采取以下步骤:

  • O 成为ToObject(base)
  • desc 成为使用属性名称​​ P 调用 O 的[[GetProperty]]内部方法的结果。
  • 如果 desc 未定义,请返回未定义
  • 如果IsDataDescriptor(desc) 为真,请返回 desc 。[[Value]]。
  • 否则,IsAccessorDescriptor(desc)必须为真,所以,让 getter desc 。[[Get]]。
  • 如果 getter 未定义,请返回 undefined
  • 返回调用 getter 的[[Call]]内部方法的结果,提供 base 作为 this 值,并且不提供任何参数。

<子> 注意在上述方法之外无法访问可能在步骤1中创建的对象。实现可能会选择避免实际创建对象。使用此内部方法的此类实际属性访问可以具有可见效果的唯一情况是它调用访问器函数时。

[1] IsPropertyReference(V)。如果基值是对象或HasPrimitiveBase(V) true ,则返回 true ;否则返回 false