为什么我需要冻结JavaScript中的对象?

Tri*_*Gao 32 javascript immutability

当有人需要Object.freeze在JavaScript中使用时,我不清楚.MDN和MSDN在有用时不提供真实的例子.我得到的部分是关于无法在运行时更改它,这是由崩溃强制执行的.问题是我什么时候才能体会到崩溃.

对我而言,不变性是一种设计时间约束,应该由类型检查器保证.

因此,在动态类型语言中发生运行时崩溃是否有任何意义,除了比以后更好地检测违规之外?

Gor*_*man 14

Object.freeze功能执行以下操作:

  • 使对象不可扩展,因此无法向其添加新属性.
  • 将对象的所有属性的可配置属性设置为false.如果--configurable为false,则无法更改属性属性,也无法删除该属性.
  • 为对象的所有数据属性将writable属性设置为false.当writable为false时,无法更改data属性值.

这是什么部分,但为什么有人会这样做?

嗯,在面向对象的范例中,存在这样的概念:现有的API包含某些不打算在其当前上下文之外进行扩展,修改或重用的元素.final各种语言中的关键字是最合适的.即使在未编译且因此易于修改的语言中,它仍然存在,即PHP,在这种情况下,JavaScript.

  • 我认为OP知道它的作用,但是想知道什么时候有用。 (2认同)
  • 在我脑海中失落的荒原中,我想起了一个 Caja 开发人员的视频,他们说他们去了委员会并要求 freeze() 以实现他们想要的安全性。我的梦想是我可以拥有一个 HTML 页面,可以安全地加载我想要的任何第三方 JS,同时仍然确保它不会执行任何我不允许的恶意行为。我认为事情的发展并不像他们希望的那么好。 (2认同)

Ply*_*ynx 10

当您拥有表示逻辑上不可变数据结构的对象时,可以使用此方法,尤其是在以下情况下:

  • 更改对象的属性或更改其"鸭子类型"可能会导致应用程序中其他位置的错误行为
  • 该对象类似于可变类型或者看起来可变,并且您希望程序员在尝试更改它时发出警告而不是获取未定义的行为.

作为API作者,这可能正是您想要的行为.例如,您可能有一个内部缓存的结构,该结构表示您通过引用提供给API用户的规范服务器响应,但仍然在内部用于各种目的.您的用户可以引用此结构,但更改它可能会导致您的API具有未定义的行为.在这种情况下,如果用户尝试修改异常,则需要抛出异常.

  • @bonomo您将未知行为和位置的问题交易到已知行为和位置之一,这是一个很好的交易.用户可以清楚地看到问题是由于他们试图改变您的API需要不可变的结构.否则,假设您的API停止响应,因为您的结构的'date`属性已被更改,您在内部用于心跳检查(例如).突然间,您的API看起来没有响应和错误,而用户认为他/她只是在做一些权宜之计(可能只是为了显示目的,比如更改时区). (7认同)
  • @bonomo作为API作者,这可能正是您想要的行为.例如,您可能有一个内部缓存的结构,该结构表示您通过引用提供给API用户的规范服务器响应,但仍然在内部用于各种目的.您的用户可以引用此结构,但更改它可能会导致您的API具有未定义的行为.在这种情况下,如果用户尝试修改异常,则需要抛出异常. (2认同)
  • 那你在争论什么?如果你说这个功能存在并且可能被滥用 - 我会同意你的看法.但是我相信Plynx在这方面做得很好,作为一个库/公共api作者,如果你想在你的代码中执行一个行为,这个*可以是一个有价值的工具.抛出异常的关键是你*希望开发人员看到它.如果你的代码抛出任何类型的异常,很可能它没有经过良好的测试 - 或者你做错了(即以非预期的方式使用库). (2认同)
  • @bonomo我认为你应该完全自由不使用它.如你所说,它不是一颗银弹.不可变数据具有其他一般优势,包括JIT围绕保证进行优化的能力(虽然我现在都不知道),以及一般安全性,如果您使用像WebStorm这样的工具进行静态分析,它可能是在运行代码之前,也会为您修改明显冻结的对象.如果您遇到的问题是Javascript是一种动态语言并在运行时抛出异常......那么是的,但不是那么......好吗? (2认同)

Pig*_*BoT 6

在我的nodejs服务器环境中,我使用freeze是出于与使用'use strict'相同的原因.如果我有一个我不想被扩展或修改的对象,我会冻结它.如果某些东西试图扩展或修改我的冻结对象,我想要我的应用程序抛出一个错误.

对我而言,这与一致,高质量,更安全的代码有关.

此外, Chrome在使用冻结对象时显示出显着的性能提升.

编辑:在我最近的项目中,我在政府实体之间发送/接收加密数据.有很多配置值.我正在使用冻结对象来获取这些值.修改这些值可能会产生严重的不良副作用.另外,正如我之前链接的那样,Chrome在冻结对象方面表现出了性能优势,我认为nodejs也是如此.

为简单起见,一个例子是:

var US_COIN_VALUE = {
        QUARTER: 25,
        DIME: 10,
        NICKEL: 5,
        PENNY: 1
    };

return Object.freeze( US_COIN_VALUE );
Run Code Online (Sandbox Code Playgroud)

没有理由修改此示例中的值.并享受速度优化带来的好处.

  • 我来自静态类型语言,在编译时强制执行不变性.我不能在所谓的"在运行时强制执行的不变性"中看到很多价值,因为违规是不可避免的,每次违规都意味着崩溃.哪个比什么都好,但比静态检查要好得多.因此我的问题是,除了利用早期崩溃试图修改所谓的不可变对象之外,还有什么呢? (2认同)

小智 5

Object.freeze主要用于函数式编程(不可移植性)

不变性是函数式编程的中心概念,因为如果没有不变性,程序中的数据流就会丢失。状态历史记录已被放弃,奇怪的错误可能会渗入您的软件中。

在JavaScript中,重要的是不要将const与不可变性混淆。const创建一个变量名绑定,创建后不能重新分配。const不会创建不可变的对象。您不能更改绑定引用的对象,但是仍然可以更改对象的属性,这意味着用const创建的绑定是可变的,而不是不变的。不变的对象根本无法更改。通过深度冻结对象,可以使值真正不变。JavaScript有一种将对象冻结一级的方法。

const a = Object.freeze({
  foo: 'Hello',
  bar: 'world',
  baz: '!'
});
Run Code Online (Sandbox Code Playgroud)


Phi*_*ppe 5

随着V8 版本 v7.6 的发布,冻结/密封阵列的性能得到了极大的提高。因此,您想要冻结对象的原因之一是当您的代码对性能至关重要时。