为什么JavaScript原语不是Objectof?

时间:2013-07-30 05:05:12

标签: javascript instanceof

今天我碰巧有太多时间可以杀死,我在Node(v0.10.13)命令行中玩了一下:

> 1 instanceof Object
false
> (1).__proto__
{}
> (1).__proto__ instanceof Object
true
> (1).__proto__.__proto__ === Object.prototype
true

现在,根据MDNinstanceof的作用是:

  

instanceof运算符测试对象是否在其原型中   链接构造函数的prototype属性。

但显然Object.prototype位于1的原型链中。那么为什么1 instanceof Object是假的呢?也许是因为1是一个原始而不是一个开头的对象?

好的,我接受了,我做了更多测试:

> (1).__proto__ === (2).__proto__
true
> 'a'.__proto__ === 'b'.__proto__
true
> (1).__proto__ === 'a'.__proto__
false
> (1).__proto__.__proto__ === 'a'.__proto__.__proto__
true
> (1).__proto__.type = 'number'
'number'
> 'a'.__proto__.type = 'string'
'string'
> (2).type
'number'
> (1.5).type
'number'
> 'b'.type
'string'

显然,所有数字基元都从一个对象继承,并且所有字符串基元都从另一个对象继承。这两个对象都继承自Object.prototype

现在问题是,如果数字和字符串被认为是原语,为什么要从其他对象继承它们?或者相反,当它们从其他对象继承时,为什么不考虑它们呢?对我来说,对象的孩子不是一个对象似乎是荒谬的。

顺便说一下,我也在Firefox 22中对它们进行了测试,得到了相同的结果。

1 个答案:

答案 0 :(得分:29)

你被一种通常被称为“拳击”(c# related articlejava related article)的机制所欺骗,这种机制会使所有遇到它的人陷入困境。你在开始时得到了正确答案:

  

也许因为1是原始而不是开始的对象?

确实如此。但是,原语如何能够包含方法?它们如何包含属性?毕竟,在js中,它们以尽可能低的水平表示(见#4.3.2)。为了使这些值真正有用,无论何时执行primitive.property,都会发生以下情况(#11.2.1):

Object(primitive).property;

换句话说,js有自动装箱。这可以用我最喜欢的技巧证明:

var primitive = 'food';
primitive.isPizza = true; //yummy
console.log(primitive.isPizza); //undefined. where did my pizza go!?
由于这拳击,

primitive.isPizza消失了:

var primitive = 'food';
Object(primitive).isPizza = true;
console.log(Object(primitive).isPizza);

盒装primitive是它自己独特的雪花 - 当你第二次装盒时,它并不是指同一件事。盒装值很快就会被GCd所遗忘,并在时间的迷雾中被遗忘。

如果你的原语不是原语,那就不会发生这种情况:

var obj = new String('food');
obj.isPizza = true;
console.log(obj.isPizza); //true

这是否意味着你应该只使用对象,而不是原语?不,原因很简单,你的时间需要在元素上存储元数据是非常少而且对象复杂化了:

obj === primitive; //false, obj is an object, primitive is a primitive