8

今天正好有太多的时间可以消磨,我在Node(v0.10.13)命令行上玩了一下:

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

现在,根据MDNinstanceof它的作用是:

instanceof 运算符测试对象的原型链中是否具有构造函数的原型属性。

但显然Object.prototypeIS 在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 中测试了这些并得到了相同的结果。

4

1 回答 1

29

您被一种通常称为“装箱”(c# 相关文章java 相关文章)的机制所欺骗,它使所有遇到它的人着迷。一开始你有正确的答案:

也许是因为 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
于 2013-07-30T05:32:21.033 回答