aguarde...

24 de março de 2021

Como congelar um objeto em JavaScript: Object.freeze (), Object.seal () e mais

Como congelar um objeto em JavaScript: Object.freeze (), Object.seal () e mais

Em JavaScript, é possível congelar um objeto, torná-lo imutável e evitar que seja alterado. Este tutorial mostrará como fazer isso. Você aprenderá como congelar um objeto em JavaScript com Object.freeze (), selá-lo com Object.seal (), evitar estendê-lo e muito mais.

Método Object.seal ()

Quando você deseja congelar um objeto em JavaScript, existem duas opções à sua escolha. A primeira opção é menos restritiva do que a segunda. Esta opção é sobre como usar o Object.seal()método. Este método ajuda a impedir que alguém adicione, remova ou reconfigure as propriedades existentes de um objeto.

JavaScript faz isso marcando todas as propriedades existentes em um objeto como não configuráveis, alterando os sinalizadores de propriedade . Isso também significa que, ao selar um objeto, não é mais possível alterar esses sinalizadores. Isso é o que significa “reconfigurar propriedades existentes”, modificar sinalizadores de propriedade.

Dito isso, selar um objeto ainda permite que você altere as propriedades que existem em um objeto. Isso ocorre porque o lacre não altera o sinalizador de escrita. Portanto, a menos que você altere o valor do writablesinalizador, você pode modificar as propriedades existentes. Sobre a sintaxe. A sintaxe de Object.seal()é simples.

Quando você deseja selar algum objeto específico, você passa esse objeto para o Object.seal()método como um argumento. Este método então retorna um novo objeto lacrado. Uma Coisa. Quando você lacra um objeto com Object.seal()você não precisa atribuir aquele objeto lacrado retornado a outra variável.

Isso criará um novo objeto lacrado e o atribuirá à nova variável. No entanto, ele também selará o objeto original que você passou para o Object.seal(). Portanto, como resultado, você terá agora dois objetos lacrados, um original e uma cópia.

// Create new object:
const myObj = {
  name: 'Joe Doe',
  age: 37
}

// Seal the "myObj" object:
Object.seal(myObj)

// Check if object is extensible:
console.log(Object.isExtensible(myObj))
// Output:
// false

// Check if object is frozen:
console.log(Object.isFrozen(myObj))
// Output:
// false

// NOTE: This will work.
// Try to change the value of "name" property:
myObj.name = 'Jack Pain'

// NOTE: This will not work.
// Try to add new properties:
myObj.occupation = 'Secret agent'
myObj.undercover = true

// NOTE: This will also not work.
// Try to remove "age" property:
delete myObj.age

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//   name: 'Jack Pain', // <= Only value of "name" prop has changed.
//   age: 37
// }


// Assigning sealed object to new variable (not necessary):
const myObj = {
  name: 'Joe Doe',
  age: 37
}

// Seal the "myObj" object and assign it to new variable:
const myObjSealed = Object.seal(myObj)

// Check if object is extensible:
console.log(Object.isExtensible(myObjSealed))
// Output:
// false

// Check if object is frozen:
console.log(Object.isFrozen(myObjSealed))
// Output:
// false

// Try to change the value of "age" in both objects:
myObj.age = 45
myObjSealed.age = 45

// Try to add new properties to both objects:
myObj.height = '90 kg'
myObjSealed.height = '90 kg'

// Try to remove "age" property:
delete myObj.age
delete myObjSealed.age

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//   name: 'Joe Doe',
//   age: 45
// }

// Log the "myObjSealed" object:
console.log(myObjSealed)
// Output:
// {
//   name: 'Joe Doe',
//   age: 45
// }

Método Object.freeze ()

Object.freeze()é a segunda opção, a mais restritiva. Embora selar um objeto permita que você altere as propriedades existentes, seus valores Object.freeze()proíbem isso. Quando você congela um objeto com Object.freeze()ele, ele ficará bloqueado. Você não poderá adicionar novas propriedades, remover ou modificar as existentes.

Além disso, o Object.freeze()método também impede que qualquer pessoa altere o protótipo do objeto . A sintaxe e a maneira de usar esse método são semelhantes a Object.seal(). A única diferença é a substituição do seal()método com freeze(), e também o resultado.

Outra coisa Object.freeze()compartilhada Object.seal()é que você também não precisa atribuir o objeto congelado retornado a uma variável. Quando você usa o Object.freeze()método, ele congela o objeto original. Se você também atribuir o objeto retornado a uma variável, você acabará apenas com dois objetos congelados.

// Create new object:
const myObj = {
  title: 'Functional Programming in JavaScript',
  author: 'Luis Atencio'
}

// Freeze the "myObj" object:
Object.freeze(myObj)

// Check if object is frozen:
console.log(Object.isFrozen(myObj))
// Output:
// true

// NOTE: This will not work.
// Try to change the value of "title" property:
myObj.title = 'Functional Programming in JavaScript: How to improve your JavaScript programs using functional techniques'

// NOTE: This will not work.
// Try to add new properties:
myObj.language = 'English'
myObj.format = 'Paperback'

// NOTE: This will also not work.
// Try to remove "author" property:
delete myObj.author

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//   title: 'Functional Programming in JavaScript',
//   author: 'Luis Atencio'
// }


// Assigning frozen object to new variable (not necessary):
const myObj = {
  title: 'Functional Programming in JavaScript',
  author: 'Luis Atencio'
}

// Freeze the "myObj" object and assign it to new variable:
const myObjFrozen = Object.freeze(myObj)

// Check if object is frozen:
console.log(Object.isFrozen(myObjFrozen))
// Output:
// true

// Try to change the value of "age" in both objects:
myObj.title = 'Functional Programming in JavaScript: How to improve your JavaScript programs using functional techniques'
myObjFrozen.title = 'Functional Programming in JavaScript: How to improve your JavaScript programs using functional techniques'

// Try to add new properties to both objects:
myObj.format = 'Paperback'
myObjFrozen.format = 'Paperback'

// Try to remove "author" property:
delete myObj.author
delete myObjFrozen.author

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//   title: 'Functional Programming in JavaScript',
//   author: 'Luis Atencio'
// }

// Log the "myObjFrozen" object:
console.log(myObjFrozen)
// Output:
// {
//   title: 'Functional Programming in JavaScript',
//   author: 'Luis Atencio'
// }

Método Object.preventExtensions ()

Selar e congelar um objeto não são as únicas opções para restringir as manipulações com objetos. Há um método adicional que você pode usar, o Object.preventExtensions(). O que esse método faz é evitar que qualquer pessoa adicione novas propriedades a um objeto. Dito isso, você ainda pode adicionar propriedades ao protótipo do objeto.

Object.preventExtensions()também não impede que você exclua propriedades existentes. A maneira de usar este método é a mesma dos dois anteriores. Você passa o objeto que deseja impedir de ser estendido e o passa como um argumento para este método. Novo objeto inextensível será retornado.

Da mesma forma que os dois métodos anteriores, você não precisa atribuir esse objeto retornado a uma variável. O Object.preventExtensions()método irá modificar o objeto original que você passou como argumento. Se você atribuí-lo, acabará com dois objetos inextensíveis em vez de um.

// Create new object:
const myObj = {
  language: 'English',
  ethnicity: 'Anglo-Saxons'
}

// Prevent "myObj" from being extended:
Object.preventExtensions(myObj)

// Check if object is extensible:
console.log(Object.isExtensible(myObj))
// Output:
// false

// Try to change the value of existing properties:
myObj.language = 'Italian'
myObj.ethnicity = 'Italians'

// Try to add new property:
myObj.languageFamily = 'Indo-European'

// Try to remove "ethnicity" property:
delete myObj.ethnicity

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//  language: 'Italian' // <= "ethnicity" has been deleted,
//                      // but no property has been added
// }


// Assigning frozen object to new variable (not necessary):
const myObj = {
  language: 'JavaScript',
  type: 'high-level'
}

// Prevent "myObj" from being extended
// and assign it to new variable:
const myObjInextensible = Object.preventExtensions(myObj)

// Check if object is extensible:
console.log(Object.isExtensible(myObj))
// Output:
// false

// Check if object is extensible:
console.log(Object.isExtensible(myObjInextensible))
// Output:
// false

// Try to add new property:
myObj.author = 'Brendan Eich'
myObjInextensible.author = 'Brendan Eich'

// Try to remove property:
delete myObj.type
delete myObjInextensible.type

// Log the "myObj" object:
console.log(myObj)
// Output:
// { language: 'JavaScript' }

// Log the "myObj" object:
console.log(myObjInextensible)
// Output:
// { language: 'JavaScript' }

Objetos profundamente congelados

Object.freeze()método permite que você congele um objeto. O Object.seal(), e também Object.preventExtensions(), permite congelar um objeto parcialmente. Dito isso, há um problema. Todos esses métodos executam apenas um congelamento “superficial”. Esses métodos congelarão apenas o próprio objeto.

Isso não será suficiente se você tiver um objeto cujas propriedades também sejam objetos. Nesse caso, esses objetos “internos” ou “aninhados” não serão congelados. Nenhum dos métodos que discutimos hoje terá qualquer efeito sobre esses objetos internos. Isso também se aplica a propriedades que são matrizes.

Uma maneira de resolver isso é usando uma recursão . Você pode criar uma função. Esta função pegará um objeto e retornará o objeto congelado com o Object.freeze()método. Dentro desta função, você irá iterar sobre todos os valores do objeto e verificar se algum valor é um objeto. Nesse caso, você chamará a função nesse valor.

// Create object for testing:
const myObj = {
  name: 'Joe',
  age: 29,
  profession: {
    title: 'Programmer',
    experience: 'senior'
  }
}

// Create function for deep freezing:
const deepFreeze = obj => {
  // Iterate over all values of provided object:
  Object.values(obj).forEach(value => {
    // Check if each value is an object:
    if (typeof value === 'object' && !Object.isFrozen(value)) {
      // If it is and if it is not frozen
      // call deepFreeze function on it:
      deepFreeze(value)
    }
  })

  // Return provided object as frozen:
  return Object.freeze(obj)
}

// Deep freeze the object:
deepFreeze(myObj)

// Check if the object itself is extensible:
console.log(Object.isExtensible(myObj))
// Output:
// false

// Check if the "inner" object is extensible:
console.log(Object.isExtensible(myObj.profession))
// Output:
// false

// Try to change properties of the object:
myObj.name = 'Jack'

// Try to change properties of the "inner" object:
myObj.profession.title = 'DevOps architect'
myObj.profession.experience = 'junior'

// Log the "myObj" object:
console.log(myObj)
// Output:
// {
//   name: 'Joe',
//   age: 29,
//   profession: { // This "inner" object is remained unchanged.
//     title: 'Programmer',
//     experience: 'senior'
//   }
// }

Descongelar?

Agora, as más notícias. Quando você congela um objeto em JavaScript, com o Object.freeze()método, você não pode descongelá-lo. Congelar um objeto é a solução definitiva. Não há como reverter isso. Uma vez que algum objeto tenha sido congelado, ele não pode ser descongelado ou modificado de qualquer forma. Isso pode parecer muito, mas é a melhor maneira de garantir que os objetos permanecerão como você os deixou.

Objetos congelados e modo estrito

Em JavaScript, existem duas variantes de JavaScript com as quais você pode trabalhar. Um é o modo desleixado . O outro é o modo estrito . O modo descuidado é o modo normal do JavaScript. É aquele com o qual você trabalha por padrão. Uma diferença entre esses dois é que o modo descuidado permite que você faça algumas coisas sem lançar uma exceção, mostrando um erro.

Um exemplo disso é a manipulação de objetos congelados. Quando você tenta fazer algo com um objeto congelado que é proibido no modo desleixado, nada acontecerá. A alteração que você deseja fazer não acontecerá e nenhum erro aparecerá. Ele falhará silenciosamente. Isso não acontecerá se você alternar para o modo estrito.

Quando você tenta manipular com propriedades de um objeto congelado, o JavaScript lançará uma exceção. Essa exceção será alguma TypeError, que dependerá especificamente do que você está tentando fazer. Se você quiser que o JavaScript lance essas exceções, mude para o modo estrito adicionando a 'use strict'instrução.

// Use strict mode:
'use strict';

// Create an object:
const myObj = {
  title: 'Functional Programming in JavaScript',
  author: 'Luis Atencio'
}

// Freeze the "myObj" object:
Object.freeze(myObj)

// Try to change the value of "title" property:
myObj.title = 'Functional Programming in JavaScript: How to improve your JavaScript programs using functional techniques'
// Output:
// TypeError: Cannot assign to read only property 'title' of object '#<Object>'

// Try to add new properties:
myObj.language = 'English'
myObj.format = 'Paperback'
// Output:
// TypeError: Cannot add property language, object is not extensible

// Try to remove "author" property:
delete myObj.author
// Output:
// TypeError: Cannot delete property 'author' of #<Object>

Conclusão: como congelar um objeto em JavaScript

Congelar objetos em JavaScript, total ou parcialmente, é fácil. Também é fácil impedir que os objetos sejam estendidos apenas com a adição de novas propriedades. Com um código de bits, você também pode garantir que os objetos congelados estejam profundamente congelados. Espero que este tutorial tenha ajudado você a entender como fazer todas essas coisas.

Postado em Blog
Escreva um comentário