2012-06-01 13 views
25

¿Cómo es que las constantes no se pueden establecer como propiedades de objetos que son variables en sí mismas?¿Cómo crear constantes Javascript como propiedades de los objetos usando la palabra clave 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 

Y cómo es que las constantes pasados ​​por referencia repente convertido en variable? EDITAR: Sé que la aplicación no (o más bien ... NO DEBE) ser mutable; esto es sólo una observación ...

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

¿Cómo puede una muy bien organizada, extensible, orientadas a objeto, por separado namespaced biblioteca que contiene las constantes pueden hacer con estas limitaciones?

EDIT: Creo zi42, pero acabo de tener que pedir why

Respuesta

33

Usted no puede hacerlo con constantes. La única forma posible de hacer algo que se comporta como lo desea, pero no está usando constantes, es definir una propiedad no se puede escribir:

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

cuanto a su pregunta de por qué un const pasa a una función pasa a ser variable, la respuesta es porque se pasa por valor y no por referencia. La función es obtener una nueva variable que tiene el mismo valor que tu constante.

edición: gracias a @pst para tomar nota de que los objetos literales en javascript en realidad no están "pasados ​​por referencia", pero utilizando call-by-sharing:

Aunque este término tiene un uso generalizado en la comunidad Python, idénticos la semántica en otros lenguajes como Java y Visual Basic a menudo se describe como llamada por valor, donde el valor implica una referencia al objeto.

+0

¿No se pasan los objetos por referencia? – danronmoon

+0

Sí, pero 'const obj = {}' es un poco inútil porque la referencia será constante, pero aún puede modificar el objeto. –

+4

No. Los objetos no son * "pasados ​​por referencia" (esta es una frase ambigua en el mejor de los casos). Una implementación generalmente "pasará * por el * valor * de la referencia", pero lo importante es que JavaScript tiene [Semántica Call By Object Sharing] (http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing). Dato curioso: * la especificación ECMAScript no usa el término "referencia" *. –

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

// works 
person.name = "Greg"; 



console.log(person) //Greg 

Es por eso que usar Object.defineProperty

1

No debe olvidó que el const declaration "crea una referencia de sólo lectura a un valor. Esto no significa que el valor que posee es inmutable, sólo que el identificador de variable no puede ser reasignado"

el trabajo palabra clave const de una manera similar a 'dejar', por lo que puede redeclare en otro bloque de

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 

Al igual que cuando se menciona a ziad-saab si desea una propiedad de objeto que no actúe como una constante, debe definirla como una propiedad no modificable.

si su constante es un objeto y la propiedad no debe cambiar, use Object.freeze() para hacer que el objeto sea inmutable.

(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

Hay una forma mucho más simple de hacerlo. Me gusta este patrón Objetos simples.

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" 

Objeto.congelación está haciendo el trabajo aquí

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

si lo desea, puede dejar la propiedad estática de la instancia dejándolo fuera del retorno literal objeto en la función constructora.

const solo la convertirá en una referencia de solo lectura. Tan pronto como lo asigne, como aquí en un objeto literal, se convierte en una propiedad del objeto construido.

Cuestiones relacionadas