Різниця між заморожуванням і ущільненням


164

Я тільки чув про методи JavaScript freezeі seal, які можуть бути використані , щоб зробити якийсь - або незмінний об'єкт.

Ось короткий приклад, як його використовувати:

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

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

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

У чому різниця між freezeі seal? Чи можуть вони підвищити продуктивність?


6
Лише зауваження для кожного, хто дивиться на це питання, прийнята відповідь фактично неправильна. @ відповідь tungd правильна.
Бьорн

2
Ще одна примітка, є також Object.preventExtensionsдодатки до Object.sealта Object.freeze. Object.preventExtensionsпросто запобігає доданню нових елементів до об'єкта. Ви можете видаляти, конфігурувати та змінювати значення властивостей об’єктів, з якими вимкнено їх розширюваність Object.preventExtensions.
Бьорн

Відповіді:


193

Object.seal

  • Це запобігає додаванню та / або видаленню властивостей із запечатаного об'єкта; використання deleteповерне помилкове
  • Це робить кожне існуюче властивість не конфігуруваним : вони не можуть бути перетворені з "дескрипторів даних" в "дескриптори доступу" (і навпаки), і жоден атрибут дескрипторів доступу не може бути змінений взагалі (тоді як дескриптори даних можуть змінювати свій writableатрибут, і їх valueатрибут, якщо writeableце правда).
  • Може кинути a TypeErrorпри спробі змінити значення самого запечатаного об'єкта (найчастіше в суворому режимі )

Object.freeze

  • Що саме Object.sealробить, плюс:
  • Це запобігає зміні будь-яких існуючих властивостей

Жоден не впливає на «глибокі» / онукові предмети. Наприклад, якщо objзаморожено, obj.elне можна перепризначити, але значення obj.elможна змінити, наприклад, obj.el.idможна змінити.


Продуктивність:

Ущільнення або заморожування об'єкта може впливати на швидкість його перерахування, залежно від браузера:

  • Firefox: на ефективність перерахування не впливає
  • IE: вплив на ефективність перерахування незначний
  • Chrome: ефективність перерахування швидша із запечатаними або замороженими об'єктами
  • Сафарі: запечатані або заморожені предмети перераховують на 92% повільніше (станом на 2014 рік)

Тести: Запечатані об'єкти , Заморожені об'єкти .


2
Чи можете ви поговорити про те, чому ми коли-небудь використовуватимемо ці методи? Просто тому, що ми можемо?
Алан Донг

3
В майбутньому я думаю, що вони будуть використовуватись багато (якщо їх правильно оптимізувати) при розробці бібліотеки / основи. Вони дозволяють запобігти користувачеві (навіть ненавмисно) порушити ваш код (і, як зазначено у відповіді, оптимізація повинна призвести до значного підвищення швидкості). Але це чисті спекуляції :)
Niccolò Campolungo

2
Ця відповідь має багато фактичних помилок. Для одного, sealтакож робить існуючі властивості неконфігуруваними , див. Jsfiddle.net/btipling/6m743whn Номер 2, ви все ще можете редагувати, тобто змінювати значення існуючих властивостей на герметичному об'єкті.
Bjorn

8
FWIW, заморожені та запечатані об'єкти тепер швидші, ніж їхні заморожені та незапечатані аналоги у Chrome Canary v43.0.2317.0.
llambda

2
@AlanDong Трохи запізнюючись, але ось чому ви хочете заблокувати об'єкт. Однією з особливостей JavaScript є те, що ви можете додати властивість будь-коли, коли вам подобається; Ви також можете це зробити випадково , неправильно ввівши текст. Багато моїх студентів намагалися додати обробника подій, що називається onClickабо onlickзапитували, чому це не працює. Якщо JavaScript видає помилку, то це одна річ, щоб помилитися. По-друге, це дозволяє реалізувати постійні властивості на об'єкті, що запобігає змінам. Це особливо корисно на об'єктних методах.
Манго

119

Я написав тестовий проект, який порівнює ці 3 методи:

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

Мої одиничні тести охоплюють випадки CRUD:

  • [C] додати нову властивість
  • [R] читати існуючу властивість
  • [U] змінити існуючу властивість
  • [D] видалити існуючу властивість

Результат:

введіть тут опис зображення


2
Це геніально. Чи враховує UPDATE зміна (за допомогою defineProperty) атрибутів дескриптора, наприклад, що можна настроювати, перелічувати, записувати?
Дренай

Я завжди хоча, що об'єкти DOM повинні бути герметичними (звичайно після поліфілів). Це допоможе запобігти багато помилок друку.
Манго

@Manngo Ви можете закріпити об'єкти DOM. Просто створіть DEBUGMODEзмінну та встановіть її true. Тоді, зробіть if (DEBUGMODE) { ... }. В ..., покладіть функціональність для забезпечення всіх об'єктів DOM завжди запечатані. Потім, коли ви будете готові розповсюджувати сценарій своєї веб-сторінки, перейдіть DEBUGMODEдо false, запустіть свій скрипт через компілятор закриття та розповсюдьте його. Це так просто.
Джек Гіффін

@JackGiffin Дякую за коментар. Я просто говорив, що завжди думав, що це буде гарна ідея. У мене дуже багато студентів, які закінчують вводити щось на кшталт element.onlick=somethingі отримують розчарування, оскільки це не працює, але технічно це не помилка.
Манго

2
@Lonely Тоді CRUD не написав би. Вам доведеться погодитися на щось на кшталт RUDE;)
Мангго

84

Ви завжди можете їх шукати в MDN. Коротко:

  • Заморожування : робить об'єкт незмінним, тобто не дозволяється зміна визначеної властивості, якщо тільки вони не є об'єктами.
  • Печать : запобігання додавання властивостей, однак визначені властивості все одно можна змінити.

1
Object.seal()також, здається, заморожені властивості прототипу: \
К ..

10

Object.freeze()створює заморожений об'єкт, що означає, що він приймає існуючий об’єкт і по суті викликає Object.seal()його, але він також позначає всі властивості "доступу даних" як writable:falseтакі, що їх значення не можуть бути змінені. - Кайл Сімпсон, Ви не знаєте JS - Цей та об'єктний прототипи


4

Я розглядав відмінності між Freeze та Seal в ECMAScript 5 і створив сценарій для уточнення відмінностей. Заморожений створює незмінний об'єкт, включаючи дані та структуру. Ущільнення запобігає змінам названих інтерфейсів - не додає, не видаляє - але ви можете вимкнути об'єкт та переосмислити значення його інтерфейсу.

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

Я знаю, що я можу трохи запізнюватися, але

  • Схожість: обидва вони використовуються для створення нерозширюваних об'єктів .
  • Різниця: у програмі Freeze можна настроювати перелічувані та записувані атрибути об'єкта false. де як у запечатаному атрибуті для запису встановлено, trueа решта атрибутів помилкові.

6
Це не зовсім правильно. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
Леон Адлер

2

Тепер ви можете змусити заморожувати властивість одного об’єкта замість заморожування всього об'єкта. Цього можна досягти за Object.definePropertyдопомогою writable: falseпараметра.

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

У цьому прикладі obj.firstтепер його значення заблоковано до 99.


0

Я створив просту таблицю для порівняння наведених нижче функцій та пояснення різниці між цими функціями.

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

Таблиця, яка пояснює різницю між вищезазначеними трьома методами

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.