2015-09-17 13 views
14

Sono stato generato con il paradigma "tutto in JavaScript orientato agli oggetti e assegnabile". Così ho vissuto felice la mia vita, fino a quando ...Perché non tutto è assegnabile in JavaScript?

var x = {}; 

x.field = true; 
x.field.netType = "System.Boolean"; 

alert(x.field.netType); 

Compila, ma l'allarme continua a dare incontrato 'undefined'. Perché!?

+4

gettare in ' 'use strict';' in alto e vedere la magia ;-) – thefourtheye

+1

@thefourtheye? cosa farebbe la modalità rigorosa qui? – Pointy

+2

@Pointy Reclami. Si lamenterebbe. La modalità rigorosa è quella ragazza schizzinosa che non ti lascia fare le cose più allettanti, mentre la modalità non rigorosa è oposite. –

risposta

19

Primitives (stringhe, numeri, true e false) in JavaScript sono non oggetti. Tuttavia, quando vengono utilizzati con . o [] come se fossero gli oggetti, il linguaggio obbliga implicitamente a costruire involucri di oggetti per loro.

Nel tuo esempio, è quello che è successo. L'assegnazione alla proprietà dell'oggetto funzionava effettivamente, quindi non c'era alcun errore, ma quell'oggetto wrapper veniva immediatamente gettato via.

D'altra parte:

var x = {}; 

x.field = new Boolean(true); 
x.field.netType = "System.Boolean"; 

alert(x.field.netType); 

(non consiglierei davvero farlo, utilizzando oggetti realizzati dai tipi wrapper primitive tende ad avere effetti strani come questi valori si propagano in codice che non si aspetta loro)

+1

C'è qualche documentazione su questo comportamento? –

+3

@ KeesC.Bakker bene c'è la [specifica della lingua] (http://www.ecma-international.org/ecma-262/5.1/) ma non è una lettura facile.Immagino che qualsiasi buon riferimento JavaScript dovrebbe toccare questo comportamento, in quanto è fondamentale per la lingua. Qualcosa di molto comune come controllare la lunghezza di una stringa causerà involucri involontari degli oggetti. – Pointy

+2

@ KeesC.Bakker: questo potrebbe interessarti: https://github.com/getify/You-Dont-Know-JS/blob/master/types%20&%20grammar/ch3.md#boxing-wrappers. Nella specifica, il boxing è definito qui: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getvalue (ma questo non è veramente prezioso senza contesto, cioè sapere come/dove ' GetValue' è chiamato). –

10
x.field = true; 
x.field.netType = "System.Boolean"; 

in realtà funziona.
x.field che è un valore booleano primitivo viene convertito in oggetto internamente ma non abbiamo un riferimento di esso così immediatamente diventa immondizia. Se memorizziamo il valore di x.field in modo che non sia spazzatura, possiamo ottenere il valore. come questo ....

x.field = true; 
var y = x.field.netType = "System.Boolean"; 
alert(y); 

Se si scrive codice come questo si

var x = {}; 

x.field = {}; 
x.field.netType = "System.Boolean"; 

alert(x.field.netType); 

allora funzionerà.

Nel codice questa linea x.field.netType = "System.Boolean"; getterà errore nel `modalità rigorosa

`//Cannot assign to read only property 'netType' of true` 

Perché questa linea x.field.netTypeundefined

oggetti di questo tipo sono soltanto involucri, il loro valore è il primitivo che avvolgere e saranno generalmente coercitivo fino a questo valore, come richiesto.

JavaScript può forzare facilmente tra primitives and objects.

var a = 'Intekhab'; 
a.length;//In this case the string value is coerced to a string object in order to access the property length. 

var Twelve = new Number(12); 
var fifteen = Twelve + 3; // In this case Object Twelve is coerced to a primitive value. 
fifteen; //15 

Se JavaScript rileva un tentativo di assegnare un immobile ad un primitivo sarà infatti costringere il primitivo a un oggetto. Questo nuovo oggetto non ha riferimenti e diventerà immediatamente un foraggio per la garbage collection.

var primitive = "september"; 
primitive.vowels = 3; 
//new object created to set property 
(new String("september")).vowels = 3; 



primitive.vowels; 
//another new object created to retrieve property 
(new String("september")).vowels; //undefined 
+2

Questa è solo la metà della risposta ... spiega perché si ottiene "undefined". ma non spiega perché il compito sembra funzionare in primo luogo. A parte questo, la domanda non era come risolvere questo problema, ma qual è la ragione di questo ... la risposta di @Pointy è * via * migliore. –

+1

Questo non è abbastanza chiaro e "sbagliato" in qualche modo perché facendo var t = new Boolean(); t.foo = "bar"; sta funzionando davvero. Può fuorviare OP. @Pointy answer è più preciso. –

+0

Avete documentazione per supportare la vostra risposta? –

5

x.field è un valore booleano; i valori booleani sono primitivi e sono di sola lettura. Quando si tenta di assegnare un valore a x.field.netType, si sta tentando di modificare il valore di x.field. La risposta di Pointy spiega principalmente questo.

In modalità JavaScript "normale", il valore è semplicemente undefined.

Il motivo per cui qualcuno nei commenti suggerito strict mode (che si dovrebbe sicuramente utilizzeranno) è che la modalità rigorosa viene generato un errore che informa che si sta tentando di assegnare un valore a un valore di sola lettura e ti impedisce di farlo invece di restituire silenziosamente undefined ogni volta che accedi a quella proprietà.

'use strict'; 
var foo = true; 
foo.bar = 'qux'; // this line will throw an Error 

Come per l'esempio di punta, lo fa in realtà errore, per lo meno sul nodo 4.0. Non ho idea di cosa stia usando il motore JS Pointy ma non funziona correttamente.

> (function() { 'use strict'; (true).x = 0; })() 
TypeError: Cannot assign to read only property 'x' of true 
    at repl:1:38 
    at repl:1:45 
    at REPLServer.defaultEval (repl.js:154:27) 
    at bound (domain.js:254:14) 
    at REPLServer.runBound [as eval] (domain.js:267:12) 
    at REPLServer.<anonymous> (repl.js:308:12) 
    at emitOne (events.js:77:13) 
    at REPLServer.emit (events.js:169:7) 
    at REPLServer.Interface._onLine (readline.js:209:10) 
    at REPLServer.Interface._line (readline.js:548:8) 
+0

@Pointy poiché non posso commentare la risposta principale, il tuo esempio e la domanda sulla modalità rigorosa sono qui. –

+0

@ mikeIl tuo nome ti sta bene! JavaScript è in effetti un linguaggio compilato JIT ed è stato da * almeno * IE9. –

+0

Noje.js utilizza il motore V8 (come Chrome), mentre noi (io e Pointy) utilizziamo Firefox. In Firefox, non c'è errore. Ma lo fa sul motore V8. –

Problemi correlati