2010-03-02 15 views
12

Me gustaría hacer la estructura de un objeto inmutable, evitando que sus propiedades sean reemplazadas posteriormente. Sin embargo, las propiedades deben ser legibles. es posible?¿Hay alguna manera de evitar el reemplazo de las propiedades del objeto JavaScript?

Estoy seguro de que no hay características de idioma (a lo largo de las líneas final en Java y readonly en C#) para soportar esto, pero me pregunto si podría haber otro mecanismo para lograr el mismo resultado.

Busco algo en este sentido:

var o = { 
    a: "a", 
    f: function() { 
     return "b"; 
    } 
}; 

var p = o.a;  // OK 
o.a = "b";   // Error 
var q = o.f();  // OK 
o.f = function() { // Error 
    return "c"; 
}; 

Respuesta

14

ECMAScript 5 tendrá seal() y freeze(), pero no hay una buena manera de hacerlo con las implementaciones de JavaScript actuales.

Source.

+1

+1: ' congelar() 'suena como lo que estoy buscando. –

+0

está ejecutando la versión 5? – mkoryak

+1

Acabo de mencionarlo como referencia. No programo activamente contra ECMAScript 5. – EndangeredMassa

9

lo mejor que puede hacer es ocultar sus propiedades en el interior de un cierre.

var getMap = function(){ 
    var hidden = "1"; 
    return { 
    getHidden : function() { return hidden; } 
    } 
} 

var f = getMap(); 

alert(f.getHidden()); 

Lo apuñalé. En el código anterior, no solo deberá devolver oculto, sino también copiarlo en un objeto nuevo. tal vez puedas usar la extensión de jquery para hacer esto por ti, por lo que devolverás un objeto nuevo, no la referencia. Aunque esto puede estar completamente equivocado =)

+0

necesito las propiedades para que sea accesible desde fuera del objeto (pregunta actualizado para reflejar) . –

+0

@Matthew Así que cree una función de acceso público. Ver mi respuesta –

+0

respuesta editada para que sea como usted quiere – mkoryak

4

Como mkoryak Dicho esto, usted puede crear un cierre para ocultar propiedades

function Car(make, model, color) { 
    var _make = make, _model = model, _color = color; 

    this.getMake = function() { 
     return _make; 
    } 

} 

var mycar = new Car("ford", "mustang", "black"); 

mycar.getMake(); //returns "ford" 
mycar._make; //error 
+0

Si mkoryak ya lo dijo, ¿por qué lo repite? – Zecc

+1

@Zecc porque esa respuesta no tenía un código de muestra originalmente –

5

Usando var en un constructor de objetos creará una variable privada. Esto es esencialmente un cierre. Luego puede crear una función pública para acceder/modificarla. Más información y ejemplos disponibles en Private Members in Javascript por Douglas Crockford.

+1

Pero luego puede reemplazar la función para devolver lo que desee. – EndangeredMassa

+0

@Sean Claro que se puede eliminar/reemplazar, pero no se puede modificar. Supongo que la conclusión es que no hay forma de reemplazar la función con algo que daría acceso directo a la var privada. –

4

Bien, entonces ya ha habido un par de respuestas que sugieren que devuelva un objeto con varios métodos getters. Pero aún puedes reemplazar esos métodos.

Esto es un poco mejor. No podrá reemplazar las propiedades del objeto sin reemplazar completamente la función. Pero todavía no es exactamente lo que quieres.

function Sealed(obj) { 
    function copy(o){ 
     var n = {}; 
     for(p in o){ 
      n[p] = o[p] 
     } 
     return n; 
    } 
    var priv = copy(obj); 
    return function(p) { 
     return typeof p == 'undefined' ? copy(priv) : priv[p]; // or maybe copy(priv[p]) 
    } 
} 

var mycar = new Sealed({make:"ford", model:"mustang", color:"black"}); 

alert(mycar('make')); // "ford" 
alert(mycar().make); // "ford" 

var newcopy = mycar(); 
newcopy.make = 'volkwagen'; 
alert(newcopy.make); // "volkwagen" :(

alert(mycar().make); // still "ford" :) 
alert(mycar('make')); // still "ford" :) 
2

Ahora puede obligar a una sola propiedad del objeto a congelar en lugar de congelar todo el objeto. Esto se puede conseguir con Object.defineProperty y el parámetro writable: false

var obj = { 
    "first": 1, 
    "second": 2, 
    "third": 3 
}; 
Object.defineProperty(obj, "first", { 
    writable: false, 
    value: 99 
}); 

En este ejemplo, obj.first tiene ahora su valor bloqueado a 99.

Cuestiones relacionadas