2014-10-09 11 views
6

On the MDN strict mode reference page es sagtseltsames Verhalten mit ‚use strict‘ und nur Eigenschaften

Jede Zuordnung lesen, die in normalen Code nicht stumm (Zuordnung zu einer nicht beschreibbaren Eigenschaft, die Zuordnung zu einer Getter-Unterkunft, die nur die Zuordnung zu eine neue Eigenschaft auf einer nicht erweiterbaren Objekt) wird

So im Strict-Modus werfen, ihr Beispiel unter Verwendung von nach so etwas wie das tun ein Auslöser Typeerror

"use strict"; 
var obj1 = {}; 
Object.defineProperty(obj1, "x", { value: 42, writable: false }); 
obj1.x = 9; // throws a TypeError 

Allerdings stieß ich auf ein Beispiel, wo es scheint, 'verwenden Sie streng' ist ein wenig übereifrig über diese Regel. Hier ist mein Setup

definelol.js

Object.defineProperty(Object.prototype, 'lol', { 
    value: 'wat' 
}) 

setlol.js

'use strict'; 

console.log('here 0'); 

var sugar = { lol: '123' } 

console.log('here 1'); 

var verbose = {}; 
verbose.lol = '123'; 

console.log('here 2'); 

console.log('sugar.lol:', sugar.lol); 
console.log('verbose.lol:', verbose.lol); 
console.log('Object.prototype.lol:', Object.prototype.lol); 

app.js

require('./definelol.js'); 
require('./setlol.js'); 

Runnin node app.js g gibt

here 0 
here 1 

/pathto/setlol.js:10 
verbose.lol = '123'; 
      ^
TypeError: Cannot assign to read only property 'lol' of #<Object> 
    at Object.<anonymous> (/pathto/setlol.js:10:13) 
    at Module._compile (module.js:456:26) 
    at Object.Module._extensions..js (module.js:474:10) 
    at Module.load (module.js:356:32) 
    at Function.Module._load (module.js:312:12) 
    at Module.require (module.js:364:17) 
    at require (module.js:380:17) 
    at Object.<anonymous> (/pathto/app.js:2:1) 
    at Module._compile (module.js:456:26) 
    at Object.Module._extensions..js (module.js:474:10) 

Es gibt ein paar interessante Dinge, die über diese Ausgabe interessant sind. Erstens versuchen wir nicht, die lol Eigenschaft auf Object.prototype zu setzen, wir versuchen, die lol Eigenschaft von verbose zu setzen. Ich definelol.js

Object.defineProperty(Object.prototype, 'lol', { 
    writable: true, 
    value: 'wat' 
}) 

Nun node app.js gibt

here 0 
here 1 
here 2 
sugar.lol: 123 
verbose.lol: 123 
Object.prototype.lol: wat 

Das zweite, was zuvor ausgeführt werden geändert, dies zu beweisen, die interessant war, dass das ursprüngliche Programm auf verbose.lol = '123' scheiterte aber war vollkommen glücklich sugar Erstellen und Einstellen seiner lol zu 123. Ich verstehe das nicht, weil es scheint, dass die Art, wie wir sugar erstellt haben, einfach syntaktischer Zucker sein sollte für die Art, wie wir verbose

erstellt haben

Antwort

3

section 11.13.1 of the spec:

sehen, wenn eine Zuordnung innerhalb der Strict-Modus-Code auftritt, muss seine LeftHandSide nicht zu einer unlösbaren Referenz bewerten. Wenn es eine ReferenceError-Ausnahme gibt, wird bei der Zuweisung ausgelöst. Die LeftHandSide-Eigenschaft darf auch keine Referenz auf eine Dateneigenschaft mit dem Attributwert {[Writable]]: false}, auf eine Accessor-Eigenschaft mit dem Attributwert {[Set]]: undefined} oder auf eine nicht vorhandene sein Eigenschaft eines Objekts, dessen interne Eigenschaft [[Extensible]] den Wert false hat. In diesen Fällen wird eine TypeError-Ausnahme ausgelöst.

In Ihrem Beispielcode, die linke Seite eines = Expression wird in der Tat, ein Verweis auf eine Daten Eigenschaft mit dem „beschreibbaren“ Flag auf false gesetzt.

Jetzt bin ich etwas sympathisch mit der Vorstellung, dass es nicht für geerbte Eigenschaften gelten sollte, aber ich kann sehen, dass es ein starkes Gegenargument geben kann. Dass das Objektliteral es ermöglicht, dass die Eigenschaft als eine "eigene" Eigenschaft des neuen "Zucker" -Objekts erzeugt wird, erscheint merkwürdig.

bearbeiten — zur Verdeutlichung, das Problem hier ist, dass die Zuordnung zu einer Objekteigenschaft immer über die Zuordnung zu einer "eigenen" Eigenschaft des Objekts. Zuweisungen beeinflussen die Eigenschaften der Vererbungskette nicht. Daher beinhaltet die gestellte Frage den folgenden scheinbaren Widerspruch: Wenn eine Eigenschaft des Objektprototyps mit dem "Schreibbar" -Flag auf false die Zuordnung zu diesem Eigenschaftsnamen auf vorhandenen-Objekten verhindert, warum ist die Zuordnung zu dieser Eigenschaft erfolgreich im Zuge der Auswertung eines Objektliterals?

Es könnte eine gute Begründung dafür geben, oder es könnte ein Fehler sein. Sowohl V8 als auch was auch immer die Firefox Laufzeit heißt (etwas-Affe ich denke) verhalten sich genauso.

+0

Haben Sie Gedanken darüber, warum die 'sugar.lol' anders behandelt wird? – Tom

+0

@Tom Nun, das ist es, was mich denken lässt, dass etwas Fischiges vor sich geht. Allerdings weiß ich nicht, welches Verhalten "falsch" genannt werden soll :) – Pointy

+1

@Tom könnte es sein, dass die "Zucker" -Ding funktioniert, weil die Objekt-Literalausdrücke definiert sind. Wenn Eigenschaften auf diese Weise definiert sind, sagt die Spezifikation explizit, dass [[DefineOwnProperty]] 'aufgerufen wird. – Pointy

0

Sie haben eine Eigenschaft für die Prototypen aller Objekte definiert, daher haben alle von ihnen eine 'lol'-Eigenschaft in ihrem Prototyp.

Zucker ist mit seinem eigenen 'lol' definiert, also hat das nichts mit dem 'lol' zu tun, das in seinem Prototyp ist. Dieser ist versteckt.

Verbose ist definiert als ein leeres Objekt, als solches wird es eine 'lol'-Eigenschaft haben, die durch seinen Prototyp zugänglich ist. Daher erstellt verbose.lol = ... keine neue Eigenschaft, sondern die Eigenschaft des Prototyps, wodurch ein Fehler auftritt, wenn Sie ihn als nicht schreibbar deklarieren.

Ich denke, es macht alles Sinn, wenn Sie so denken.

EDIT: Das ist nicht der richtige Weg, es zu sehen, lesen Sie die Kommentare

+0

So funktionieren die Dinge in JavaScript nicht. Wenn Sie * einer Eigenschaft eine * zuweisen (vergessen Sie die "schreibbare" Sache vorerst), ** ändern Sie ** niemals vererbte Eigenschaften - Sie beeinflussen das Objekt immer direkt. Das heißt, wenn Sie einer Eigenschaft eines Objekts zuweisen, ob eine vererbbare Eigenschaft mit dem referenzierten Namen vorhanden ist oder nicht, erhalten Sie immer eine "eigene" Eigenschaft des Zielobjekts. – Pointy

+1

Sie haben vollkommen recht. Wie die von Ihnen angegebene Spezifikation besagt, verhält sich der strikte Modus so, als ob Sie versuchen würden, die Eigenschaft des Prototyps zu ändern, aber letztendlich wird nur die Eigenschaft des Objekts geändert, wenn alle Prüfungen in Ordnung sind. Das ist ein bisschen komisch. – Greg