为什么JavaScript原语不是Object的instanceof?

Why are JavaScript primitives not instanceof Object?

今天我碰巧有太多时间要杀死,我在Node(v0.10.13)命令行上玩了一点:

1
2
3
4
5
6
7
8
> 1 instanceof Object
false
> (1).__proto__
{}
> (1).__proto__ instanceof Object
true
> (1).__proto__.__proto__ === Object.prototype
true

现在,根据MDN,instanceof的作用是:

The instanceof operator tests whether an object has in its prototype
chain the prototype property of a constructor.

但是很明显,Object.prototype IS在1的原型链中。那么1 instanceof Object为什么是假的?也许是因为1是原始图元,而不是开头的对象?

好的,我接受了,并且进行了更多测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> (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中对它们进行了测试,并得到了相同的结果。


您被一种通常被称为"装箱"的机制所迷惑(与c#相关的文章,与Java有关的文章),使所有碰到它的人着迷。开始时您有正确的答案:

Perhaps because 1 is a primitive not an object to begin with?

就是这样。但是,原语如何能够包含方法?它们如何包含属性?毕竟,在js中,它们以尽可能最低的级别表示(请参阅#4.3.2)。为了使这些值实际有用,无论何时执行primitive.property,都会发生以下情况(#11.2.1):

1
Object(primitive).property;

换句话说,js具有自动装箱功能。可以使用我最喜欢的技巧之一来证明这一点:

1
2
3
var primitive = 'food';
primitive.isPizza = true; //yummy
console.log(primitive.isPizza); //undefined. where did my pizza go!?

primitive.isPizza由于此拳击而消失:

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

装箱的primitive是它自己独特的雪花-再次装箱时,它指的不是同一件事。装箱的值会很快被GCd识别,并在时间的迷雾中被遗忘。

如果您的原始图元不是原始图元,则不会发生这种情况:

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

这是否意味着您应该只使用对象,而不能使用基元?不,原因很简单,您确实需要在元数据上存储元数据的时间非常少,而对象使事情变得复杂:

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