2015-09-17 5 views
14

Ich wurde mit dem Paradigma "alles in JavaScript objektorientiert und zuweisbar" angesprochen. So lebte ich mein Leben glücklich, bis ...Warum ist nicht alles in JavaScript zuweisbar?

var x = {}; 

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

alert(x.field.netType); 

Es kompiliert, aber die Warnung traf hält Geben ‚undefined‘. Warum!?

+4

Wurf in ' 'use strict',' an der Spitze und die Magie sehen ;-) – thefourtheye

+1

@thefourtheye? Was würde der strikte Modus hier tun? – Pointy

+2

@Pointy Beschweren. Es würde sich beschweren. Strenger Modus ist das wählerische Mädchen, das dich nicht das verlockendste Zeug machen lässt, während der nicht-strikte Modus das Gegenteil ist. –

Antwort

19

Primitives (Strings, Zahlen, true und false) in JavaScript sind nicht Objekte. Wenn sie jedoch mit . oder [] so verwendet werden, als wären sie Objekte, verpflichtet die Sprache, implizit Objektwrapper für sie zu konstruieren.

In Ihrem Beispiel ist das passiert. Die Zuweisung zu der Objekteigenschaft hat tatsächlich funktioniert, also gab es keinen Fehler, aber dieses Wrapperobjekt wurde dann sofort weggeworfen.

Auf der anderen Seite:

var x = {}; 

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

alert(x.field.netType); 

(würde ich nicht raten tatsächlich, das zu tun, mit Objekten aus den primitiven Wrapper-Typen gemacht neige seltsame Effekte zu haben, wie diese Werte in dem Code verbreiten, die nicht erwarten, nicht sie.)

+1

Gibt es Dokumentation zu diesem Verhalten? –

+3

@ KeesC.Bakker gut gibt es die [Sprachspezifikation] (http://www.ecma-international.org/ecma-262/5.1/), aber das ist nicht leicht zu lesen.Ich würde mir vorstellen, dass jede gute JavaScript-Referenz dieses Verhalten berühren müsste, da es ziemlich grundlegend für die Sprache ist. Etwas Ähnliches wie das Überprüfen der Länge eines Strings führt zu einem impliziten Objektumbruch. – Pointy

+2

@ KeesC.Bakker: Das könnte Sie interessieren: https://github.com/getify/You-Dont-Know-JS/blob/master/types%20&%20grammar/ch3.md#boxing-wrappers. In der Spezifikation ist das Boxen hier definiert: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getvalue (aber das ist nicht wirklich wertvoll ohne Kontext, dh zu wissen, wie/wo? GetValue wird aufgerufen). –

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

funktioniert tatsächlich.
x.field was ein primitiver Boolescher Wert ist, wird intern in Objekt konvertiert, aber wir haben keine Referenz davon, so dass es sofort zu Müll wird. Wenn wir den Reference von x.field speichern, so dass es kein Müll ist, können wir den Wert erhalten. wie folgt ....

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

Wenn Sie Sie dieses

var x = {}; 

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

alert(x.field.netType); 

Code schreiben, dann wird es funktionieren.

In Ihrem Code diese Zeile x.field.netType = "System.Boolean"; Fehler in `Strict-Modus sie

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

Warum diese Linie x.field.netType gibt undefined

Objekte dieser Art sind nur Wrapper, ist ihr Wert die primitive werfen wrap und sie werden in der Regel auf diesen Wert nach Bedarf herunterdrücken.

JavaScript wird zwischen primitives and objects problemlos erzwingen.

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 

Wenn JavaScript versucht wird, eine Eigenschaft zu einem primitiven zuweisen er tatsächlich die primitiven zu einem Objekt zwingen wird. Dieses neue Objekt hat keine Referenzen und wird sofort zum Garbage Collection-Objekt.

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

Dies ist nur die halbe Antwort ... es erklärt, warum Sie "undefiniert" bekommen. aber es erklärt nicht, warum der Auftrag an erster Stelle zu arbeiten scheint. Abgesehen davon, die Frage war nicht, wie das zu beheben, aber was ist der Grund dafür ... die Antwort von @ Pointy ist * Weg * besser. –

+1

Dies ist nicht klar genug und in irgendeiner Weise "falsch", weil var t = new Boolean(); t.foo = "bar"; arbeitet tatsächlich. Es kann OP irreführen. @ Pointy Antwort ist genauer atm. –

+0

Haben Sie Unterlagen, die Ihre Antwort unterstützen? –

5

x.field ist ein boolescher Wert; Boolesche Werte sind Primitive und sind schreibgeschützt. Wenn Sie versuchen, einen Wertzuzuweisen, versuchen Sie, den Wert von x.field zu ändern. Pointys Antwort erklärt das meistens.

Im 'normalen' JavaScript-Modus lautet der Wert einfach .

Der Grund warum jemand in den Kommentaren Strict-Modus vorgeschlagen (die Sie definitiv verwenden sollten) ist, dass der Strict-Modus einen Fehler aus, werden Sie darüber informiert, dass Sie einen Wert auf einen Nur-Lese-Wert zuweisen versuchen und verhindern, dass Sie das tun, anstatt undefined bei jedem Zugriff auf diese Eigenschaft stillschweigend zurückzugeben.

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

Wie pro Zipfel Vorbild, es funktioniert tatsächlich Fehler, zumindest auf Knoten 4.0. Ich habe keine Ahnung, was JS Engine Pointy benutzt, aber es funktioniert nicht richtig.

> (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, da ich die Hauptantwort nicht kommentieren kann, Ihr Beispiel und die Frage nach dem strikten Modus sind hier. –

+0

@mikeTheLiar Ihr Name steht Ihnen gut! JavaScript ist in der Tat eine JIT-kompilierte Sprache und ist seit * mindestens * IE9. –

+0

Noje.js verwendet die V8-Engine (wie Chrome), während wir (ich und Pointy) Firefox verwenden. In Firefox gibt es keinen Fehler. Aber es tut es auf dem V8-Motor. –

Verwandte Themen