2013-07-30 12 views
8

Oggi mi è capitato di avere troppo tempo per uccidere e ho giocato un po 'con la linea di comando Node (v0.10.13):Perché le primitive JavaScript non sono instanceof Object?

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

Ora, secondo MDN, ciò che fa è instanceof:

L'operatore instanceof verifica se un oggetto ha nel suo prototipo la proprietà prototipo di un costruttore.

Ma chiaramente Object.prototype IS nel prototipo di catena 1. Allora, perché 1 instanceof Object è falso? Forse perché lo 1 non è un oggetto primitivo per cominciare?

Va bene, accetto che, e l'ho fatto più test:

> (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' 

Quindi, apparentemente tutte le primitive numero ereditano da un oggetto, e tutte le primitive stringa ereditare da un altro oggetto. Entrambi questi 2 oggetti ereditano da Object.prototype.

Ora la domanda è: se numeri e stringhe sono considerati primitivi, perché ereditarli da altri oggetti? Oppure inversamente, poiché ereditano da altri oggetti, perché non considerarli anche loro oggetti? Sembra assurdo che il figlio di un oggetto non sia un oggetto ..

A proposito, ho anche provato questi in Firefox 22 e ho ottenuto lo stesso risultato.

risposta

25

Sei stato ingannato da un meccanismo comunemente noto come "boxing" (c# related article, java related article) che incanta tutti quelli che lo incontrano. All'inizio avevi la risposta corretta:

Forse perché 1 è un primitivo non un oggetto per cominciare?

Esattamente. Tuttavia, come possono le primitive essere mai in grado di contenere metodi? Come possono contenere proprietà? Dopo tutto, in js, sono rappresentati al livello più basso possibile (vedi #4.3.2). Per rendere questi valori effettivamente utile, ogni volta che si fa primitive.property, accade quanto segue (#11.2.1):

Object(primitive).property; 

In altre parole, js ha pugilato automatico. Questo può essere dimostrato utilizzando uno dei miei trucchi preferiti:

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

primitive.isPizza scomparso a causa di questa boxe:

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

Il boxed primitive è il suo fiocco di neve unico - quando si Box una seconda volta, si non si riferisce alla stessa cosa I valori in scatola sono rapidamente GCd e dimenticati nella notte dei tempi.

Questo non succede se il primitivo non è, beh, un primitivo:

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

Questo significa che si dovrebbe usare solo gli oggetti, mai primitivi? No, per il semplice motivo che i tempi si fanno necessità di memorizzare i meta-dati sulle primitive sono molto pochi e rari, e gli oggetti complicare le cose:

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

Grande risposta, grazie. –

+0

Tutti i miei +1 vanno da te! – Greg

+0

Myne 2 .... :-). –

Problemi correlati