如何在 JavaScript 中冻结对象:Object.freeze()、Object.seal() 等
在 JavaScript 中,可以冻结一个对象,使其不可变,并防止其被更改。本教程将向您展示如何操作。您将学习如何在 JavaScript 中使用 Object.freeze() 冻结对象、使用 Object.seal() 密封对象、防止其被扩展等等。
Object.seal() 方法
当你想在 JavaScript 中冻结一个对象时,有两种方法可供选择。第一种方法比第二种方法限制较少。这种方法与方法有关Object.seal()
。此方法可帮助你阻止任何人添加、删除或重新配置对象的现有属性。
JavaScript 通过将对象中所有现有属性标记为不可配置(即更改属性标志)来实现这一点。这也意味着,当你密封一个对象时,你将无法再更改这些标志。这就是“重新配置现有属性”的含义,即修改属性标志。
话虽如此,密封对象仍然允许您更改对象中现有的属性。这是因为密封不会更改可写标志。因此,除非您更改writable
标志的值,否则您可以修改现有属性。关于语法。的语法Object.seal()
很简单。
当你想要密封某个特定对象时,你可以将该对象Object.seal()
作为参数传递给该方法。该方法随后返回新的密封对象。需要注意的是,当你使用密封对象时,Object.seal()
无需将返回的密封对象赋值给其他变量。
这样做会创建一个新的密封对象并将其赋值给新变量。但是,它也会密封传递给 的原始对象Object.seal()
。因此,现在您将拥有两个密封对象,一个原始对象和一个副本。
// 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
// }
Object.freeze() 方法
这Object.freeze()
是第二种选择,限制性更强。虽然密封对象允许您更改现有属性及其值,但Object.freeze()
禁止这样做。冻结对象后,Object.freeze()
它将被锁定。您将无法添加新属性,也无法删除或修改现有属性。
除此之外,该Object.freeze()
方法还能防止任何人更改对象原型。该方法的语法和使用方法与类似。唯一的区别是将方法Object.seal()
替换为,以及结果也不同。seal()
freeze()
另一个Object.freeze()
共同点Object.seal()
是,您也不必将返回的冻结对象赋值给变量。使用该Object.freeze()
方法时,它会冻结原始对象。如果您也将返回的对象赋值给变量,最终只会得到两个冻结对象。
// 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'
// }
Object.preventExtensions() 方法
密封和冻结对象并非限制对象操作的唯一方法。您还可以使用另一种方法,即Object.preventExtensions()
。此方法的作用是阻止任何人向对象添加新属性。即便如此,您仍然可以向对象原型添加属性。
这Object.preventExtensions()
也不会阻止您删除现有属性。此方法的使用方法与前两个方法相同。您将要阻止扩展的对象作为参数传递给此方法。将返回一个新的不可扩展对象。
与前两种方法类似,您无需将返回的对象赋值给变量。该Object.preventExtensions()
方法将修改您作为参数传递的原始对象。如果您赋值,最终将得到两个不可扩展的对象,而不是一个。
// 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' }
深度冷冻的物体
方法Object.freeze()
允许您冻结对象。Object.seal()
以及 也Object.preventExtensions()
允许您部分冻结对象。不过,有一个问题。所有这些方法都仅执行“浅”冻结。这些方法只会冻结对象本身。
如果您的对象本身的属性也是对象,那么这还不够。在这种情况下,这些“内部”或“嵌套”对象将不会被冻结。我们今天讨论的任何方法都不会对这些内部对象产生任何影响。这同样适用于数组属性。
解决这个问题的一种方法是使用递归。你可以创建一个函数。该函数接受一个对象作为参数,并返回一个使用该Object.freeze()
方法冻结的对象。在这个函数内部,你将迭代该对象的所有值,并检查是否有任何值是对象。如果是,则对该值调用该函数。
// 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'
// }
// }
解冻?
现在说说坏消息。在 JavaScript 中,当你使用该Object.freeze()
方法冻结一个对象时,你就无法解冻它了。冻结对象是最终的解决方案,没有办法逆转它。一旦某个对象被冻结,它就无法解冻,也无法以任何方式修改。这看起来可能有点过分,但这是确保对象保持原样的最佳方法。
冻结对象和严格模式
在 JavaScript 中,有两种 JavaScript 变体可供使用。一种是松散模式,另一种是严格模式。松散模式是 JavaScript 的正常模式,也是默认使用的模式。两者之间的一个区别是,松散模式允许你执行某些操作而不会引发异常,也不会显示错误。
一个例子就是操作冻结对象。当你尝试对冻结对象执行某些在松散模式下被禁止的操作时,什么也不会发生。你想要进行的更改将不会发生,也不会出现任何错误。它会静默地失败。如果你切换到严格模式,就不会发生这种情况。
当你尝试操作冻结对象的属性时,JavaScript 会抛出异常。异常的具体类型TypeError
取决于你尝试执行的操作。如果你想让 JavaScript 抛出这些异常,请通过添加以下'use strict'
语句切换到严格模式。
// 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>
结论:如何在 JavaScript 中冻结对象
在 JavaScript 中,完全或部分冻结对象都很容易。通过添加新属性来阻止对象扩展也很容易。只需几行代码,你就可以确保冻结的对象深度冻结。希望本教程能帮助你理解如何操作所有这些操作。
文章来源:https://dev.to/alexdevero/how-to-freeze-an-object-in-javascript-object-freeze-object-seal-more-4n46