Diferencia entre congelar y sellar

164

Acabo de escuchar acerca de los métodos de JavaScript freezey seal, que se pueden usar para hacer que cualquier Objeto sea inmutable.

Aquí hay un breve ejemplo de cómo usarlo:

var o1 = {}, o2 = {};
Object.freeze(o2);

o1["a"] = "worked";
o2["a"] = "worked";

alert(o1["a"]);   //prints "worked"
alert(o2["a"]);   //prints "undefined"

¿Cuál es la diferencia entre freezey seal? ¿Pueden aumentar el rendimiento?

maja
fuente
66
Solo una nota para cualquiera que esté mirando esta pregunta, la respuesta aceptada es objetivamente incorrecta. La respuesta de @ tungd es correcta.
Bjorn
2
Otra nota, también hay Object.preventExtensionsademás de Object.sealy Object.freeze. Object.preventExtensionssolo evita que se agreguen nuevos elementos a un objeto. Puede eliminar, configurar y cambiar los valores de las propiedades en los objetos que tenían su extensibilidad desactivada Object.preventExtensions.
Bjorn

Respuestas:

193

Object.seal

  • Evita agregar y / o eliminar propiedades del objeto sellado; utilizando deletedevolverá falso
  • Hace que todas las propiedades existentes no sean configurables : no se pueden convertir de 'descriptores de datos' a 'descriptores de acceso' (y viceversa), y ningún atributo de descriptores de acceso puede modificarse en absoluto (mientras que los descriptores de datos pueden cambiar su writableatributo, y su valueatributo si writeablees verdadero).
  • Puede lanzar un TypeErroral intentar modificar el valor del objeto sellado en sí (más comúnmente en modo estricto )

Object.freeze

  • Exactamente qué Object.sealhace, más:
  • Evita modificar cualquier propiedad existente

Ninguno de los dos afecta a los objetos 'profundos' / nietos. Por ejemplo, si objestá congelado, obj.elno se puede reasignar, pero obj.else puede modificar el valor de , por ejemplo, obj.el.idse puede cambiar.


Actuación:

Sellar o congelar un objeto puede afectar su velocidad de enumeración, dependiendo del navegador:

  • Firefox: el rendimiento de la enumeración no se ve afectado
  • IE: el impacto en el rendimiento de la enumeración es insignificante
  • Chrome: el rendimiento de enumeración es más rápido con objetos sellados o congelados
  • Safari: los objetos sellados o congelados se enumeran un 92% más lento (a partir de 2014)

Pruebas: objetos sellados , objetos congelados .

Niccolò Campolungo
fuente
2
¿Puedes hablar sobre por qué usaríamos estos métodos? ¿Solo porque podemos?
Alan Dong
3
En el futuro, creo que se usarán mucho (si se optimizan correctamente) al desarrollar una biblioteca / marco. Le permiten evitar que el usuario rompa (incluso sin querer) su código (y, como se indica en la respuesta, las optimizaciones deberían conducir a grandes mejoras de velocidad). Pero esto es pura especulación :)
Niccolò Campolungo
2
Esta respuesta tiene muchos errores de hecho. Por un lado, sealtambién hace que las propiedades existentes no sean configurables, consulte jsfiddle.net/btipling/6m743whn Número 2, aún puede editar, es decir, cambiar los valores de las propiedades existentes en un objeto sellado.
Bjorn
8
FWIW, los objetos congelados y sellados ahora son más rápidos que sus equivalentes no congelados y sin sellar en Chrome Canary v43.0.2317.0.
llambda
2
@AlanDong Un poco tarde en llegar, pero esta es la razón por la que desea bloquear un objeto. Una de las características de JavaScript es que puede agregar una propiedad en cualquier momento; También puede hacer esto accidentalmente escribiendo mal. Muchos de mis estudiantes han tratado de añadir un controlador de eventos llamada onClicko onlick, y se preguntó por qué no está funcionando. Si JavaScript arroja un error, entonces esa es una cosa menos para equivocarse. En segundo lugar, esto le permite implementar propiedades constantes en un objeto que evita cambios. Esto es particularmente útil en métodos de objeto.
Manngo
119

Escribí un proyecto de prueba que compara estos 3 métodos:

  • Object.freeze()
  • Object.seal()
  • Object.preventExtensions()

Las pruebas de mi unidad cubren casos de CRUD:

  • [C] agregar nueva propiedad
  • [R] leer propiedad existente
  • [U] modificar propiedad existente
  • [D] eliminar propiedad existente

Resultado:

ingrese la descripción de la imagen aquí

piecioshka
fuente
2
Esto es brillante. ¿ACTUALIZACIÓN tiene en cuenta la modificación (a través de defineProperty) de los atributos del descriptor, por ejemplo, configurable, enumerable, editable?
Drenai
Siempre pensé que los objetos DOM deberían estar sellados (después de polyfills, por supuesto). Eso ayudaría a evitar muchos errores tipográficos.
Manngo
@Manngo Puede sellar sus objetos DOM. Simplemente cree una DEBUGMODEvariable y configúrela como true. Entonces hazlo if (DEBUGMODE) { ... }. En el ..., coloque su funcionalidad para garantizar que todos los objetos DOM estén siempre sellados. Luego, cuando esté listo para distribuir el script página web, el cambio DEBUGMODEa false, ejecute la secuencia de comandos a través del compilador de cierre, y distribuirlo. Es tan simple como eso.
Jack Giffin
@JackGiffin Gracias por el comentario. Solo decía que siempre pensé que sería una buena idea. Tengo muchos estudiantes que terminan escribiendo algo así element.onlick=somethingy frustrados porque no funciona, pero técnicamente no es un error.
Manngo
2
@ Solo Entonces no significaría CRUDO. Tendrías que conformarte con algo como RUDE;)
Manngo
84

Siempre puedes buscarlos en MDN. En breve:

  • Congelar : hace que el objeto sea inmutable, lo que significa que no se permiten cambios en la propiedad definida, a menos que sean objetos.
  • Sello : evita la adición de propiedades, sin embargo, las propiedades definidas aún se pueden cambiar.
tungd
fuente
1
Object.seal()También parece congelar las propiedades del prototipo: \
K ..
10

Object.freeze()crea un objeto congelado, lo que significa que toma un objeto existente y esencialmente lo invoca Object.seal(), pero también marca todas las propiedades de "acceso a datos" como writable:false, de modo que sus valores no se pueden cambiar. - Kyle Simpson, You Don't Know JS - This & Object Prototypes

shmuli
fuente
4

Estaba mirando las diferencias entre Freeze y Seal en ECMAScript 5 y creé un script para aclarar las diferencias. Frozen crea un objeto inmutable que incluye datos y estructura. Seal evita los cambios en las interfaces con nombre (sin adiciones ni eliminaciones), pero puede mutar el objeto y redefinir el significado de su interfaz.

function run()
{
    var myObject = function() 
    { 
        this.test = "testing"; 
    }

    //***************************SETUP****************************

    var frozenObj = new myObject();
    var sealedObj = new myObject();

    var allFrozen = Object.freeze(frozenObj);
    var allSealed = Object.seal(sealedObj);
    alert("frozenObj of myObject type now frozen - Property test= " + frozenObj.test);
    alert("sealedObj of myObject type now frozen - Property test= " + sealedObj.test);

    //***************************FROZEN****************************

    frozenObj.addedProperty = "added Property"; //ignores add
    alert("Frozen addedProperty= " + frozenObj.addedProperty);
    delete frozenObj.test; //ignores delete
    alert("Frozen so deleted property still exists= " + frozenObj.test);
    frozenObj.test = "Howdy"; //ignores update
    alert("Frozen ignores update to value= " + frozenObj.test);
    frozenObj.test = function() { return "function"; } //ignores
    alert("Frozen so ignores redefinition of value= " + frozenObj.test);

    alert("Is frozen " + Object.isFrozen(frozenObj));
    alert("Is sealed " + Object.isSealed(frozenObj));
    alert("Is extensible " + Object.isExtensible(frozenObj));

    alert("Cannot unfreeze");
    alert("result of freeze same as the original object: " + (frozenObj === allFrozen).toString());

    alert("Date.now = " + Date.now());

    //***************************SEALED****************************

    sealedObj.addedProperty = "added Property"; //ignores add
    alert("Sealed addedProperty= " + sealedObj.addedProperty);
    sealedObj.test = "Howdy"; //allows update
    alert("Sealed allows update to value unlike frozen= " + sealedObj.test);
    sealedObj.test = function() { return "function"; } //allows
    alert("Sealed allows redefinition of value unlike frozen= " + sealedObj.test);
    delete sealedObj.test; //ignores delete
    alert("Sealed so deleted property still exists= " + sealedObj.test);
    alert("Is frozen " + Object.isFrozen(sealedObj));
    alert("Is sealed " + Object.isSealed(sealedObj));
    alert("Is extensible " + Object.isExtensible(sealedObj));

    alert("Cannot unseal");
    alert("result of seal same as the original object: " + (sealedObj === allSealed).toString());

    alert("Date.now = " + Date.now());
}
Jaycee
fuente
3

Sé que puedo llegar un poco tarde pero

  • Similitud: ambos se utilizan para crear objetos no extensibles .
  • Diferencia: en Freeze , los atributos configurables, enumerables y de escritura del objeto se establecen en false. donde, como en Sealed, el atributo de escritura se establece en truey el resto de los atributos son falsos.
Faisal Naseer
fuente
66
Esto no es del todo correcto. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
Leon Adler
2

Ahora puede forzar la congelación de una propiedad de un solo objeto en lugar de congelar todo el objeto. Puede lograr esto Object.definePropertycon writable: falsecomo parámetro.

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

En este ejemplo, obj.firstahora tiene su valor bloqueado en 99.

jaggedsoft
fuente
0

He creado una tabla simple para comparar las funciones a continuación y explicar la diferencia entre estas funciones.

  • Object.freeze ()
  • Object.seal ()
  • Object.preventExtensions ()

tabla que explica la diferencia entre los tres métodos anteriores

Shwetabh Shekhar
fuente