ES6 Set,WeakSet,Map和WeakMap

ncu*_*ica 5 javascript ecmascript-6

关于地图和弱地图已经存在一些问题,例如:ES6 Map和WeakMap有什么区别?但我想问一下,在哪种情况下我应该赞成使用这些数据结构?或者当我偏爱其他人时,我应该考虑什么呢?

来自以下网址的数据结构示例:https://github.com/lukehoban/es6features

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set
Run Code Online (Sandbox Code Playgroud)

奖金.以上哪个数据结构将产生相同/相似的结果:let hash = object.create(null); hash[index] = something;

T.J*_*der 11

这在规范的§23.3中有所涉及:

如果用作WeakMap键/值对的键的对象只能通过跟随WeakMap从其开始的引用链来到达,则该键/值对不可访问并自动从中删除WeakMap.

因此,弱映射中的条目(如果它们的键未被其他任何东西引用)将在某个时刻被垃圾收集回收.

相比之下,a Map拥有对其键的引用,如果映射是引用它们的唯一事物,则防止它们被垃圾收集.

MDN 这样说:

a中的关键WeakMap是弱的.这意味着,如果没有对密钥的其他强引用,则整个条目将从WeakMap垃圾收集器中删除.

WeakSet做同样的.

...在哪种情况下我应该支持使用这种数据结构?

在任何情况下,您不希望使用密钥来映射/设置该事实,以防止该密钥被垃圾收集.

您可能使用此功能的一个示例是具有特定于实例的信息,该信息对于实例而言是真正私有的,如下所示:

let Thing = (() => {
    var privateData = new WeakMap();

    class Thing {
        constructor() {
            privateData[this] = {
                foo: "some value"
            };
        }

        doSomething() {
            console.log(privateData[this].foo);
        }
    }

    return Thing;
})();
Run Code Online (Sandbox Code Playgroud)

除了作用域函数之外的代码无法访问数据privateData.该数据由实例本身键入.如果没有a,你就不会这样做,WeakMap因为如果你有内存泄漏,你的Thing实例永远不会被清除.但是WeakMap只包含引用,因此如果使用Thing实例的代码完成并释放对实例的引用,WeakMap则不会阻止实例被垃圾回收; 相反,实例键入的条目将从地图中删除.

以上哪个数据结构将产生相同/相似的结果: let hash = Object.create(null); hash[index] = something;

这将是最接近的Map,因为字符串index(属性名称)将由对象中的强引用保持(如果没有其他任何引用它,则它及其相关属性将不会被回收).

  • 我这周一直在研究 ES6/TypeScript,这一定是我第 30 次遇到并从您的答案中受益,现在我希望接受的答案是您的答案。感谢您投入如此多的时间和精力来帮助这个社区和其他开发人员。 (4认同)
  • @LogicalBranch - 天哪,谢谢!我真的很感谢你花时间这么说。:-) (2认同)