能否将Set(或Map)“冻结”起来?

21

虽然Set是一个对象,Object.freeze()作用于对象的属性,而显然Map和Set不使用:例如

let m = new Map();
Object.freeze(m);
m.set('key', 55);
m.get('key'); // ==> 55

这是在Chrome中的行为,我认为这是标准的。
我理解有时可以将Set或Map转换为普通对象,然后冻结该对象,但是在未冻结和冻结版本之间键访问会发生变化。

1
你使用哪个Set和Map?我在JavaScript中没有看到这样的。 - MaxZoom
1
@MaxZoom:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set - cc young
移动浏览器显示效果不佳。 - MaxZoom
除非您使用类似Babel的工具将其转换为ES5和/或使用polyfill,否则@MaxZoom无法正常运行。 - Alexander O'Mara
1个回答

10

这是一个有趣的问题,但目前似乎不是SetMap对象上直接支持的功能。

以下是一些我可以想到使用Set对象作为指南的解决方法:

  1. 你可以创建一个代理对象,删除.add().clear().delete(),但允许代理访问所有其他仅读数据的方法。这将隐藏对实际Set对象的访问,因此没有直接访问它并提供代理访问所有其他方法的方式。

  2. 你可以覆盖给定Set实例上的.add().clear().delete(),使其成为什么都不做或抛出异常的方法,从而防止修改。如果您使这些重写方法不可配置,然后对对象执行.freeze(),这些方法将无法被放回。 但是,可以直接在Set对象上使用Set.prototype.add绕过它。


感谢。同意。第一种方法似乎需要很多工作,而且会失去“instanceof Set”的功能。第二种方法,覆盖“.add()”等方法,似乎更容易,可以使其静默失败或引发错误。至于“仍然绕过”,对我来说,冻结的主要优点不是绝对安全,而是像变量类型一样保护自己。 - cc young
1
虽然已经有几年了,但我想提一下,如果您用undefined覆盖列出的方法而不是方法,那么解决方案#2将最有效。如果您尝试将它们作为方法调用,这将引发错误,并且对于一次性操作来说最容易。如果您想要一个更通用的解决方案,使用子类化Set或Map,请记住这些在所有浏览器中都无法正确子类化,因此#1中的代理是更好的可重用方法。 - Ryan Hanekamp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接