Różnica między zamrożeniem a uszczelnieniem


164

Właśnie usłyszałem o metodach JavaScript freezei seal, które można wykorzystać do uczynienia dowolnego obiektu niezmiennym.

Oto krótki przykład, jak go używać:

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

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

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

Jaka jest różnica między freezei seal? Czy mogą zwiększyć wydajność?


6
Tylko uwaga dla każdego, kto patrzy na to pytanie, przyjęta odpowiedź jest niezgodna ze stanem faktycznym. Odpowiedź @ tungd jest poprawna.
— Bjorn

2
Kolejna uwaga, Object.preventExtensionsoprócz Object.seali Object.freeze. Object.preventExtensionspo prostu zapobiega dodawaniu nowych elementów do obiektu. Możesz usuwać, konfigurować i zmieniać wartości właściwości obiektów, dla których wyłączono ich rozszerzalność za pomocą Object.preventExtensions.
— Bjorn

Odpowiedzi:


193

Object.seal

  • Zapobiega dodawaniu i / lub usuwaniu właściwości z zapieczętowanego obiektu; użycie deletezwróci fałsz
  • Sprawia, że żadna istniejąca właściwość nie jest konfigurowalna : nie można ich konwertować z `` deskryptorów danych '' na `` deskryptory akcesorów '' (i odwrotnie), a żaden atrybut deskryptorów akcesorów nie może być w ogóle modyfikowany (podczas gdy deskryptory danych mogą zmieniać swój writableatrybut, oraz ich valueatrybut, jeśli writeablejest prawdziwy).
  • Może rzucić a TypeErrorpodczas próby zmodyfikowania wartości samego zapieczętowanego obiektu (najczęściej w trybie ścisłym )

Object.freeze

  • Dokładnie to Object.seal, co robi, a ponadto:
  • Zapobiega modyfikacji żadnych istniejących obiektów

Żaden z nich nie wpływa na obiekty „głębokie” / wnuki. Np. Jeśli objjest zamrożone, obj.elnie można go ponownie przypisać, ale wartość obj.elmożna zmodyfikować, np. obj.el.idMożna ją zmienić.


Występ:

Zapieczętowanie lub zamrożenie obiektu może wpłynąć na szybkość jego wyliczania w zależności od przeglądarki:

  • Firefox: nie ma to wpływu na wydajność wyliczania
  • IE: wpływ na wydajność wyliczenia jest znikomy
  • Chrome: wydajność wyliczania jest szybsza w przypadku obiektów zamkniętych lub zamrożonych
  • Safari: zamknięte lub zamrożone obiekty wyliczają 92% wolniej (od 2014 r.)

Testy: Sealed obiekty , zamrożone obiekty .


2
Czy możesz porozmawiać o tym, dlaczego mielibyśmy kiedykolwiek używać tych metod? Tylko dlatego, że możemy?
— Alan Dong

3
Myślę, że w przyszłości będą one często używane (jeśli zostaną odpowiednio zoptymalizowane) podczas tworzenia biblioteki / frameworka. Pozwalają one zapobiec (nawet niezamierzonemu) użytkownikowi złamania kodu (i, jak stwierdzono w odpowiedzi, optymalizacje powinny prowadzić do znacznej poprawy szybkości). Ale to czysta spekulacja :)
— Niccolò Campolungo

2
Ta odpowiedź zawiera wiele błędów rzeczowych. Po pierwsze, sealsprawia , że istniejące właściwości nie są konfigurowalne, patrz jsfiddle.net/btipling/6m743whn Numer 2, nadal można edytować, to znaczy zmieniać wartości istniejących właściwości w zamkniętym obiekcie.
— Bjorn

8
FWIW, zamrożone i zapieczętowane obiekty są teraz szybsze niż ich niezamrożone i niezapieczętowane odpowiedniki w Chrome Canary w wersji 43.0.2317.0.
— llambda

2
@AlanDong Trochę za późno, ale oto dlaczego chcesz zablokować obiekt. Jedną z cech JavaScript jest to, że możesz dodać właściwość w dowolnym momencie; możesz to również zrobić przypadkowo , błędnie wpisując. Wielu moich uczniów próbowało dodać program obsługi zdarzeń o nazwie onClicklub onlicki zastanawiali się, dlaczego nie działa. Jeśli JavaScript zgłasza błąd, to o jedną rzecz mniej do popełnienia błędu. Po drugie, pozwala to na zaimplementowanie stałych właściwości obiektu, co zapobiega zmianom. Jest to szczególnie przydatne w przypadku metod obiektowych.
— Manngo,

119

Napisałem projekt testowy, który porównuje te 3 metody:

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

Moje testy jednostkowe obejmują przypadki CRUD:

  • [C] dodaj nową właściwość
  • [R] odczyt istniała własność
  • [U] zmodyfikuj istniejącą właściwość
  • [D] usuń istniejącą właściwość

Wynik:

wprowadź opis obrazu tutaj


2
To jest genialne. Czy UPDATE uwzględnia modyfikację (poprzez defineProperty) atrybutów deskryptora, np. Konfigurowalne, wyliczalne, zapisywalne?
— Drenai,

Zawsze uważałem, że obiekty DOM powinny być zapieczętowane (oczywiście po polyfillach). Pomogłoby to uniknąć wielu błędów literówek.
— Manngo,

@Manngo Możesz zapieczętować swoje obiekty DOM. Po prostu utwórz DEBUGMODEzmienną i ustaw ją na true. Następnie zrób if (DEBUGMODE) { ... }. W programie ...umieść swoją funkcjonalność zapewniającą, że wszystkie obiekty DOM są zawsze zapieczętowane. Następnie, gdy jesteś gotowy do dystrybucji skryptu strony internetowej, zmień DEBUGMODEgo false, uruchom skrypt za pomocą kompilatora zamknięcia i rozpowszechnij go. To takie proste.
— Jack Giffin,

@JackGiffin Dzięki za komentarz. Mówiłem tylko, że zawsze uważałem, że to dobry pomysł. Mam wielu uczniów, którzy w końcu piszą coś podobnego element.onlick=somethingi są sfrustrowani, ponieważ to nie działa, ale technicznie nie jest to błąd.
— Manngo,

2
@ Samotny Wtedy nie przeliterowałoby CRUD. Musiałbyś zadowolić się czymś w rodzaju RUDE;)
— Manngo

84

Zawsze możesz je sprawdzić w MDN. W skrócie:

  • Freeze : sprawia, że ​​obiekt jest niezmienny, co oznacza, że ​​żadna zmiana zdefiniowanej właściwości nie jest dozwolona, ​​chyba że są to obiekty.
  • Pieczęć : zapobiega dodawaniu właściwości, jednak zdefiniowane właściwości nadal można zmienić.

1
Object.seal()również wydaje się zamrażać właściwości prototypu: \
— K ..

10

Object.freeze()tworzy zamrożony obiekt, co oznacza, że ​​pobiera istniejący obiekt i zasadniczo go wywołuje Object.seal(), ale także oznacza wszystkie właściwości „ elementu dostępu do danych” jako writable:false, aby nie można było zmienić ich wartości. - Kyle Simpson, You Don't Know JS - This & Object Prototypes


4

Patrzyłem na różnice między Freeze i Seal w ECMAScript 5 i stworzyłem skrypt, aby wyjaśnić różnice. Frozen tworzy niezmienny obiekt, w tym dane i strukturę. Pieczęć zapobiega zmianom w nazwanych interfejsach - nie dodaje, nie usuwa - ale możesz zmutować obiekt i przedefiniować znaczenie jego interfejsu.

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());
}

3

Wiem, że mogę się trochę spóźnić, ale

  • Podobieństwo: oba są używane do tworzenia obiektów nierozszerzalnych .
  • Różnica: W konfigurowalnych Freeze , wyliczalne i zapisywalne atrybuty obiektu są ustawione na false. gdzie jak w Sealed writable atrybut jest ustawiony na, truea pozostałe atrybuty są false.

6
To nie jest całkowicie poprawne. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
— Leon Adler

2

Możesz teraz wymusić zamrożenie pojedynczej właściwości obiektu zamiast zamrażania całego obiektu. Można to osiągnąć z Object.definePropertyze writable: falsejako parametr.

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

W tym przykładzie obj.firstjego wartość jest teraz zablokowana na 99.


0

Stworzyłem prostą tabelę, aby porównać poniższe funkcje i wyjaśnić różnicę między tymi funkcjami.

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

tabela wyjaśniająca różnicę między powyższymi trzema metodami

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.