如何在 JavaScript 中冻结对象:Object.freeze()、Object.seal() 等

2025-06-04

如何在 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
// }
Enter fullscreen mode Exit fullscreen mode

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'
// }
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

深度冷冻的物体

方法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'
//   }
// }
Enter fullscreen mode Exit fullscreen mode

解冻?

现在说说坏消息。在 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>
Enter fullscreen mode Exit fullscreen mode

结论:如何在 JavaScript 中冻结对象

在 JavaScript 中,完全或部分冻结对象都很容易。通过添加新属性来阻止对象扩展也很容易。只需几行代码,你就可以确保冻结的对象深度冻结。希望本教程能帮助你理解如何操作所有这些操作。

文章来源:https://dev.to/alexdevero/how-to-freeze-an-object-in-javascript-object-freeze-object-seal-more-4n46
PREV
JavaScript 中的柯里化简介
NEXT
如何在 HTML 和 CSS 中链接 Unsplash 图片 将 Unsplash 图片链接到 HTML 标签。将 Unsplash 图片链接到 CSS 规则 总结