Différence entre congeler et sceller

164

Je viens d'entendre parler des méthodes JavaScript freezeet seal, qui peuvent être utilisées pour rendre tout objet immuable.

Voici un petit exemple comment l'utiliser:

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

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

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

Quelle est la différence entre freezeet seal? Peuvent-ils augmenter les performances?

maja
la source
6
Juste une note à quiconque regarde cette question, la réponse acceptée est factuellement incorrecte. La réponse de @ tungd est correcte.
Bjorn
2
Une autre note, il y a aussi Object.preventExtensionsen plus de Object.sealet Object.freeze. Object.preventExtensionsempêche simplement de nouveaux éléments d'être ajoutés à un objet. Vous pouvez supprimer, configurer et modifier les valeurs des propriétés d’objets dont l’extensibilité est désactivée avec Object.preventExtensions.
Bjorn

Réponses:

193

Object.seal

  • Il empêche l'ajout et / ou la suppression de propriétés de l'objet scellé; l'utilisation deleteretournera false
  • Cela rend toutes les propriétés existantes non configurables : elles ne peuvent pas être converties de `` descripteurs de données '' en `` descripteurs d'accesseurs '' (et vice versa), et aucun attribut de descripteurs d'accesseurs ne peut être modifié du tout (alors que les descripteurs de données peuvent changer leur writableattribut, et leur valueattribut si writeableest vrai).
  • Peut lancer un TypeErrorlors d' une tentative de modification de la valeur de l'objet scellé lui-même (le plus souvent en mode strict )

Object.freeze

  • Exactement ce que Object.sealfait, plus:
  • Il empêche la modification des propriétés existantes

Aucun des deux n'affecte les objets «profonds» / petits-enfants. Par exemple, si objest gelé, obj.elne peut pas être réaffecté, mais la valeur de obj.elpourrait être modifiée, par exemple obj.el.idpeut être modifiée.


Performance:

Le scellement ou le gel d'un objet peut affecter sa vitesse d'énumération, selon le navigateur:

  • Firefox: les performances d'énumération ne sont pas impactées
  • IE: l'impact sur les performances d'énumération est négligeable
  • Chrome: les performances d'énumération sont plus rapides avec des objets scellés ou gelés
  • Safari: les objets scellés ou gelés dénombrent 92% plus lentement (à partir de 2014)

Tests: objets scellés , objets congelés .

Niccolò Campolungo
la source
2
Pouvez-vous expliquer pourquoi nous utiliserions ces méthodes un jour? Juste parce que nous pouvons?
Alan Dong
3
À l'avenir, je pense qu'ils seront beaucoup utilisés (s'ils sont optimisés correctement) lors du développement d'une bibliothèque / d'un framework. Ils vous permettent d'empêcher l'utilisateur de casser (même involontairement) votre code (et, comme indiqué dans la réponse, les optimisations devraient conduire à de grandes améliorations de la vitesse). Mais c'est de la pure spéculation :)
Niccolò Campolungo
2
Cette réponse comporte de nombreuses erreurs factuelles. D'une part, sealrend également les propriétés existantes non configurables, voir jsfiddle.net/btipling/6m743whn Numéro 2, vous pouvez toujours modifier, c'est-à-dire modifier les valeurs des propriétés existantes sur un objet scellé.
Bjorn
8
Les objets FWIW, gelés et scellés sont désormais plus rapides que leurs homologues non gelés et non scellés dans Chrome Canary v43.0.2317.0.
llambda
2
@AlanDong Un peu tard, mais voici pourquoi vous voulez verrouiller un objet. L'une des fonctionnalités de JavaScript est que vous pouvez ajouter une propriété à tout moment; vous pouvez également le faire accidentellement en tapant mal. Beaucoup de mes étudiants ont essayé d'ajouter un gestionnaire d'événements appelé onClickou onlicket se sont demandé pourquoi cela ne fonctionnait pas. Si JavaScript génère une erreur, c'est une chose de moins à se tromper. Deuxièmement, cela vous permet d'implémenter des propriétés constantes sur un objet, ce qui empêche les modifications. Ceci est particulièrement utile sur les méthjods d'objets.
Manngo
119

J'ai écrit un projet de test qui compare ces 3 méthodes:

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

Mes tests unitaires couvrent les cas CRUD:

  • [C] ajouter une nouvelle propriété
  • [R] read existait une propriété
  • [U] modifier la propriété existante
  • [D] supprimer une propriété existante

Résultat:

entrez la description de l'image ici

piecioshka
la source
2
C'est génial. UPDATE prend-il en compte la modification (via defineProperty) des attributs du descripteur, par exemple configurable, énumérable, inscriptible?
Drenai
J'ai toujours pensé que les objets DOM devraient être scellés (après les polyfills, bien sûr). Cela aiderait à éviter de nombreuses erreurs typographiques.
Manngo
@Manngo Vous pouvez sceller vos objets DOM. Créez simplement une DEBUGMODEvariable et définissez-la sur true. Alors fais if (DEBUGMODE) { ... }. Dans le ..., mettez vos fonctionnalités pour vous assurer que tous les objets DOM sont toujours scellés. Ensuite, lorsque vous êtes prêt à distribuer votre script de page Web , passez DEBUGMODEà false, exécutez votre script via le compilateur de fermeture et distribuez-le. C'est aussi simple que ça.
Jack Giffin
@JackGiffin Merci pour le commentaire. Je disais simplement que j'ai toujours pensé que ce serait une bonne idée. J'ai beaucoup d'étudiants qui finissent par taper quelque chose du genre element.onlick=somethinget qui deviennent frustrés parce que cela ne fonctionne pas, mais ce n'est pas techniquement une erreur.
Manngo
2
@Lonely Alors ça n'épellerait pas CRUD. Vous auriez à vous contenter de quelque chose comme RUDE;)
Manngo
84

Vous pouvez toujours les rechercher dans MDN. En bref:

  • Figer : rend l'objet immuable, ce qui signifie qu'aucune modification de la propriété définie n'est autorisée, sauf s'il s'agit d'objets.
  • Sceau : empêche l'ajout de propriétés, mais les propriétés définies peuvent encore être modifiées.
tungd
la source
1
Object.seal()semble également geler les propriétés du prototype: \
K ..
10

Object.freeze()crée un objet figé, ce qui signifie qu'il prend un objet existant et l'appelle essentiellement Object.seal(), mais il marque également toutes les propriétés de l '«accesseur de données» comme writable:false, de sorte que leurs valeurs ne peuvent pas être modifiées. - Kyle Simpson, vous ne connaissez pas JS - Prototypes ceci et objet

shmuli
la source
4

Je regardais les différences entre Freeze et Seal dans ECMAScript 5 et j'ai créé un script pour clarifier les différences. Frozen crée un objet immuable comprenant des données et une structure. Seal empêche les modifications des interfaces nommées - pas d'ajouts, ni de suppressions - mais vous pouvez muter l'objet et redéfinir la signification de son interface.

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
la source
3

Je sais que je suis peut-être un peu en retard mais

  • Similitude: les deux sont utilisés pour créer des objets non extensibles .
  • Différence: dans Freeze , les attributs configurables, énumérables et inscriptibles de l'objet sont définis sur false. où, comme dans l' attribut inscriptible scellé, est défini sur trueet le reste des attributs est faux.
Faisal Naseer
la source
6
Ce n'est pas tout à fait correct. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
Leon Adler
2

Vous pouvez maintenant forcer une propriété d'objet unique à être gelée au lieu de geler l'objet entier. Vous pouvez y parvenir Object.definePropertyavec writable: falsecomme paramètre.

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

Dans cet exemple, a obj.firstmaintenant sa valeur verrouillée à 99.

déchiqueté
la source
0

J'ai créé un tableau simple pour comparer les fonctions ci-dessous et expliquer la différence entre ces fonctions.

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

tableau qui explique la différence entre les trois méthodes ci-dessus

Shwetabh Shekhar
la source