2012-06-01 9 views
25

Come mai le costanti non possono essere impostate come proprietà di oggetti che sono variabili stesse?Come creare costanti Javascript come proprietà degli oggetti usando la parola chiave const?

const a = 'constant' // all is well 
// set constant property of variable object 
const window.b = 'constant' // throws Exception 
// OR 
var App = {}; // want to be able to extend 
const App.goldenRatio= 1.6180339887 // throws Exception 

E come mai le costanti passate per riferimento diventano improvvisamente variabili? EDIT: So che l'App non sarà (o piuttosto ... NON DEVE) essere mutabile; questa è solo un'osservazione ...

(function() { 
    const App; 
    // bunch of code 
    window.com_namespace = App; 
}()); 
window.com_namespace; // App 
window.com_namespace = 'something else'; 
window.com_namespace; // 'something else' 

Come può un ben organizzato, estensibile, orientato agli oggetti, singolarmente namespace libreria contenente costanti essere fatta con queste limitazioni?

EDIT: Credo zi42, ma devo solo chiedere why

risposta

33

Non si può farlo con costanti. L'unico modo possibile per fare qualcosa che si comporta come si vuole, ma non utilizza le costanti, è quello di definire una struttura non-scrivibile:

var obj = {}; 
Object.defineProperty(obj, "MY_FAKE_CONSTANT", { 
    value: "MY_FAKE_CONSTANT_VALUE", 
    writable: false, 
    enumerable: true, 
    configurable: true 
}); 

quanto riguarda la tua domanda sul perché un const passato a una funzione diventa variabile, la risposta è perché è passato per valore e non per riferimento. La funzione sta ricevendo una nuova variabile che ha lo stesso valore della tua costante.

modifica: grazie a @pst per notare che gli oggetti letterali in javascript non sono effettivamente "passati dal riferimento", ma utilizzando call-by-sharing:

Anche se questo termine ha diffuso utilizzo nella comunità Python, identico la semantica in altri linguaggi come Java e Visual Basic sono spesso descritti come call-by-value, dove il valore è implicito come riferimento all'oggetto.

+0

Gli oggetti non sono passati per riferimento? – danronmoon

+0

Sì, ma 'const obj = {}' è abbastanza inutile perché il riferimento sarà costante, ma è comunque possibile modificare l'oggetto. –

+4

No. Gli oggetti sono * non * "passati per riferimento" (questa è una frase ambigua al meglio). Un'implementazione generalmente "passa per * valore * del riferimento" ma l'importante è che JavaScript abbia [semantica di Call By Object Sharing] (http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing). Fatto divertente: * la specifica ECMAScript non usa il termine "riferimento" *. –

3
const person = { 
    name: "Nicholas" 
}; 

// works 
person.name = "Greg"; 



console.log(person) //Greg 

Ecco perché utilizzare Object.defineProperty

1

Non si dovrebbe dimenticato che il const declaration "crea un riferimento di sola lettura per un valore. Questo non significa il valore che detiene è immutabile, solo che l'identificativo variabile non può essere riassegnato"

il lavoro parola chiave const in un modo simile di 'lasciare', in modo da poter ridichiarare in un altro blocco

const MyConst = 5; 
console.log('global MyConst =', MyConst); //global MyConst = 5 
if(true){ 
    const MyConst = 99 
    console.log('in if block, MyConst =', MyConst); //in if block, MyConst = 99 
} 
console.log('global MyConst still 5 ?', MyConst===5); //global MyConst still 5 ? true 

Proprio come @ ziad-saab con funzione se si desidera una proprietà dell'oggetto che si comporta come una costante, è necessario definirla come proprietà non scrivibile.

se la costante è un oggetto e la proprietà non deve cambiare, utilizzare Object.freeze() per rendere l'oggetto immutabile.

(function(){ 
    var App = { }; 
    // create a "constant" object property for App 
    Object.defineProperty(App , "fixedStuff", { 
    value: Object.freeze({ prop:6 }), 
    writable: false, 
    enumerable: true, 
    configurable: true 
    }); 

    Object.defineProperty(window, "com_namespace", { 
    value: App, 
    writable: false, 
    enumerable: true, 
    configurable: true 
    }); 
})() 

com_namespace.newStuff = 'An extension'; 
com_namespace.fixedStuff.prop = 'new value'; // do nothing! 
console.log(com_namespace.fixedStuff.prop); //6 
3

C'è un modo molto più semplice per farlo. Mi piace questo modello. Oggetti semplici.

window.Thingy = (function() { 

    const staticthing = "immutable"; 

    function Thingy() { 

     let privateStuff = "something"; 

     function get() { 
      return privateStuff; 
     } 

     function set(_) { 
      privateStuff = _; 
     } 
     return Object.freeze({ 
      get, 
      set, 
      staticthing 
     }); 
    } 

    Thingy.staticthing = staticthing; 
    return Object.freeze(Thingy); 
})(); 

let myThingy = new Thingy(); 

Thingy.staticthing = "fluid"; 

myThingy.staticthing = "fluid"; 

console.log(Thingy.staticthing); // "immutable" 
console.log(myThingy.staticthing); // "immutable" 

Oggetto.congelamento sta facendo il lavoro qui

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

se volete potete lasciare la proprietà statica fuori l'istanza, lasciando fuori il ritorno letterale oggetto sulla funzione di costruzione.

const renderà solo un riferimento di sola lettura. Non appena lo assegni, come qui in un oggetto letterale, diventa una proprietà dell'oggetto costruito.

Problemi correlati