Diferença entre congelar e vedar

164

Acabei de ouvir falar dos métodos JavaScript freezee seal, que podem ser usados ​​para tornar qualquer objeto imutável.

Aqui está um pequeno exemplo de como usá-lo:

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

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

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

Qual é a diferença entre freezee seal? Eles podem aumentar o desempenho?

maja
fonte
6
Apenas uma observação para qualquer pessoa que esteja olhando para essa pergunta, a resposta aceita está factualmente incorreta. A resposta de @ tungd está correta.
Bjorn
2
Outra nota, também há Object.preventExtensionsalém de Object.seale Object.freeze. Object.preventExtensionsapenas impede que novos itens sejam adicionados a um objeto. Você pode excluir, configurar e alterar os valores das propriedades em objetos com a extensibilidade desativada Object.preventExtensions.
Bjorn

Respostas:

193

Object.seal

  • Evita adicionar e / ou remover propriedades do objeto selado; usando deleteretornará falso
  • Torna todas as propriedades existentes não configuráveis : elas não podem ser convertidas de 'descritores de dados' em 'descritores de acessadores' (e vice-versa), e nenhum atributo dos descritores de acessores pode ser modificado (enquanto os descritores de dados podem alterar seu writableatributo e seusvalue atributo se writeablefor verdadeiro).
  • Pode lançar um TypeErrorao tentar modificar o valor do próprio objeto selado (geralmente no modo estrito )

Object.freeze

  • O que exatamente Object.seal faz, mais:
  • Impede modificar quaisquer propriedades existentes

Nenhum deles afeta objetos "profundos" / netos. Por exemplo, se objestá congelado, obj.elnão pode ser reatribuído, mas o valor de obj.elpode ser modificado, por exemplo, obj.el.idpode ser alterado.


Atuação:

Selar ou congelar um objeto pode afetar sua velocidade de enumeração, dependendo do navegador:

  • Firefox: o desempenho da enumeração não é afetado
  • IE: o impacto no desempenho da enumeração é insignificante
  • Chrome: o desempenho da enumeração é mais rápido com objetos fechados ou congelados
  • Safari: objetos selados ou congelados enumeram 92% mais lento (a partir de 2014)

Testes: Objetos selados , Objetos congelados .

Niccolò Campolungo
fonte
2
Você pode falar sobre o porquê de usarmos esses métodos? Só porque nós podemos?
Alan Dong
3
No futuro, acho que eles serão usados ​​muito (se otimizados corretamente) ao desenvolver uma biblioteca / estrutura. Eles permitem que você impeça o usuário (mesmo que não intencionalmente) de quebrar seu código (e, como indicado na resposta, as otimizações devem levar a grandes melhorias de velocidade). Mas isso é pura especulação :)
Niccolò Campolungo
2
Esta resposta tem muitos erros factuais. Por um lado, sealtambém torna as propriedades existentes não configuráveis, consulte jsfiddle.net/btipling/6m743whn Número 2, você ainda pode editar, ou seja, alterar os valores das propriedades existentes em um objeto selado.
Bjorn
8
Agora, os objetos congelados e selados do FWIW agora são mais rápidos que seus equivalentes não congelados e não lacrados no Chrome Canary v43.0.2317.0.
11285 llambda
2
@AlanDong Um pouco tarde, mas aqui está o porquê de você bloquear um objeto. Um dos recursos do JavaScript é que você pode adicionar uma propriedade a qualquer momento; você também pode fazer isso acidentalmente digitando incorretamente. Muitos de meus alunos tentaram adicionar um manipulador de eventos chamado onClickou onlicke se perguntaram por que ele não está funcionando. Se o JavaScript gerar um erro, é menos uma coisa a se enganar. Em segundo lugar, isso permite implementar propriedades constantes em um objeto que impede alterações. Isso é particularmente útil em métodos de objetos.
Manngo
119

Eu escrevi um projeto de teste que compara esses 3 métodos:

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

Meus testes de unidade abrangem casos CRUD:

  • [C] adicione nova propriedade
  • [R] propriedade existente de leitura
  • [U] modificar propriedade existente
  • [D] remover propriedade existente

Resultado:

insira a descrição da imagem aqui

piecioshka
fonte
2
Isto é brilhante. O UPDATE leva em consideração a modificação (via defineProperty) dos atributos do descritor, por exemplo, configurável, enumerável, gravável?
Drenai 22/09
Sempre achei que os objetos DOM deveriam ser selados (depois dos polyfills, é claro). Isso ajudaria a evitar muitos erros de digitação.
Manngo
@Manngo Você pode selar seus objetos DOM. Simplesmente crie uma DEBUGMODEvariável e defina-a true. Então faça if (DEBUGMODE) { ... }. No ..., coloque sua funcionalidade para garantir que todos os objetos DOM estejam sempre lacrados. Em seguida, quando estiver pronto para distribuir o script da página da Web, altere DEBUGMODEpara false, execute o script pelo compilador de fechamento e distribua-o. É simples assim.
Jack Giffin
@ JackGiffin Obrigado pelo comentário. Eu só estava dizendo que sempre achei que seria uma boa ideia. Muitos estudantes acabam digitando algo comoelement.onlick=something e ficam frustrados porque não funciona, mas tecnicamente não é um erro.
Manngo 5/09/18
2
@Lonely Então não seria soletrar CRUD. Você teria que se contentar com algo como RUDE;)
Manngo
84

Você sempre pode procurá-los no MDN. Em resumo:

  • Congelar : torna o objeto imutável, o que significa que nenhuma alteração na propriedade definida é permitida, a menos que sejam objetos.
  • Selo : evita a adição de propriedades, no entanto, as propriedades definidas ainda podem ser alteradas.
tungd
fonte
1
Object.seal()também parece congelar as propriedades do protótipo: \
K ..
10

Object.freeze()cria um objeto congelado, o que significa que ele pega um objeto existente e essencialmente o chama Object.seal(), mas também marca todas as propriedades de "acessador de dados" como writable:false, para que seus valores não possam ser alterados. - Kyle Simpson, você não conhece JS - Este e protótipos de objetos

shmuli
fonte
4

Eu estava olhando para as diferenças entre Freeze e Seal no ECMAScript 5 e criei um script para esclarecer as diferenças. Frozen cria um objeto imutável, incluindo dados e estrutura. O selo evita alterações nas interfaces nomeadas - sem acréscimos, exclusões - mas você pode alterar o objeto e redefinir o significado de sua 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
fonte
3

Eu sei que posso me atrasar um pouco, mas

  • Semelhança: os dois são usados ​​para criar objetos não extensíveis .
  • Diferença: No Freeze configurável, atributos enumeráveis ​​e graváveis do objeto são definidos como false. onde, como no atributo gravável selado, é definido como truee o restante dos atributos é falso.
Faisal Naseer
fonte
6
Isso não é inteiramente correto. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
31516 Leon Adler
2

Agora você pode forçar uma propriedade de um único objeto a ser congelada em vez de congelar o objeto inteiro. Você pode conseguir isso com Object.definePropertywith writable: falsecomo um parâmetro.

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

Neste exemplo, obj.firstagora seu valor está bloqueado para 99.

jaggedsoft
fonte
0

Criei uma tabela simples para comparar as funções abaixo e explicar a diferença entre essas funções.

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

tabela que explica a diferença entre os três métodos acima

Shwetabh Shekhar
fonte