ECMAScript 6: WeakSet 的用途是什么?

WeakSet 应该通过弱引用存储元素。也就是说,如果某个对象没有被其他任何对象引用,则应该从 WeakSet 中清除该对象。

我写了以下的测试:

var weakset = new WeakSet(),
numbers = [1, 2, 3];


weakset.add(numbers);
weakset.add({name: "Charlie"});


console.log(weakset);


numbers = undefined;


console.log(weakset);

即使我的 [1, 2, 3]数组没有被任何东西引用,它也不会从 WeakSet 中删除:

WeakSet {[1, 2, 3], Object {name: "Charlie"}}
WeakSet {[1, 2, 3], Object {name: "Charlie"}}

为什么?

另外,我还有一个问题: 直接向 WeakSet 添加对象的意义何在:

weakset.add({name: "Charlie"});

是 Traceur 的故障还是我遗漏了什么?

最后,如果我们甚至不能迭代 WeakSet,也不能得到当前的大小,那么 WeakSet 的实际用途是什么?

16325 次浏览

根据定义,WeakSet只有三个关键功能

  • 将对象弱链接到集合中
  • 从集合中删除指向对象的链接
  • 检查对象是否已链接到集合

听起来更熟悉吗?

在某些应用程序中,开发人员可能需要实现一种快速的方法来遍历一系列被大量冗余 但是你只想选择那些以前没有处理过的(唯一的)所污染的数据。弱集可以帮你。请看下面的例子:

var processedBag = new WeakSet();
var nextObject = getNext();
while (nextObject !== null){
// Check if already processed this similar object?
if (!processedBag.has(nextObject)){
// If not, process it and memorize
process(nextObject);
processedBag.add(nextObject);
}
nextObject = getNext();
}

上述应用程序的最佳数据结构之一是 Bloom 过滤器,它非常适合大规模数据。但是,您也可以为此目的应用 弱势群体

没有从弱势群体中移除,为什么?

很可能是因为垃圾回收器尚未运行。但是,您说您正在使用 Traceur,所以可能它们没有得到适当的支持。我想知道 console怎样才能显示 WeakSet的内容。

直接向 WeakSet 添加对象有什么意义?

绝对没有必要向 WeakSet添加对象文字。

如果我们甚至不能迭代 WeakSet,也得不到当前的大小,那么 WeakSet 的实际用途是什么?

您所能得到的只是一点信息: 对象(或者一般来说,值)是否包含在集合中?

在您想要“标记”对象而不实际改变它们(设置它们的属性)的情况下,这可能很有用。许多算法包含某种“如果 x已经被看到”的条件(一个 JSON.stringify循环检测可能是一个很好的例子) ,当您使用用户提供的值时,使用 Set/WeakSet将是明智的。在这里,WeakSet的优势在于它的内容可以在算法仍在运行时进行垃圾收集,因此当您处理大量生成的数据时,它有助于减少内存消耗(甚至防止泄漏)。

这个问题很难回答。老实说,在 JavaScript所以我在讨论中问道的上下文中我完全不知道,但是从 Domenic那里得到了一个令人信服的答案。

由于 保安确认的原因,弱集是有用的。如果您希望能够隔离一段 JavaScript。它们允许您 标签一个对象,以表明它属于一组特殊的对象。

假设我有一个类 ApiRequest:

class ApiRequest {
constructor() {
// bring object to a consistent state, use platform code you have no direct access to
}


makeRequest() {
// do work
}
}

现在,我正在编写一个 JavaScript 平台-我的平台允许你运行 JavaScript 来进行调用-来进行那些调用,你需要一个 ApiRequest-我只希望你使用我给你的对象来进行 ApiRequest,这样你就不能绕过我设置的任何约束。

然而,目前没有什么能阻止你去做:

ApiRequest.prototype.makeRequest.call(null, args); // make request as function
Object.create(ApiRequest.prototype).makeRequest(); // no initialization
function Foo(){}; Foo.prototype = ApiRequest.prototype; new Foo().makeRequest(); // no super

等等,请注意,您不能保留 ApiRequest对象的普通列表或数组,因为这样会防止对它们进行垃圾回收。除了闭包之外,任何事情都可以通过诸如 Object.getOwnPropertyNamesObject.getOwnSymbols这样的公共方法来实现。所以你抢了我的风头:

const requests = new WeakSet();
class ApiRequest {
constructor() {
requests.add(this);
}


makeRequest() {
if(!request.has(this)) throw new Error("Invalid access");
// do work
}
}

现在,无论我做什么-我必须持有一个有效的 ApiRequest对象来调用它的 makeRequest方法。如果没有 WeakMap/WeakSet,这是不可能的。

简而言之,就是 WeakMaps 对于用 JavaScript 编写平台非常有用。通常这种类型的验证是在 C + + 端完成的,但是添加这些特性将允许在 JavaScript 中移动和创建内容。

(当然,WeakSet执行的将值映射到 trueWeakMap也可以执行,但对于任何 map/set 构造都是如此)

(正如 Bergi 的回答所暗示的那样,从来没有理由直接向 WeakMapWeakSet添加对象文字)

WeakSet 是对 WeakMap 的简化,其中的值始终为布尔值。它允许您标记 JavaScript 对象,以便只对它们执行一次操作,或者针对某个进程维护它们的状态。理论上,由于它不需要保存一个值,所以它应该比 WeakMap 使用更少的内存,并且执行速度略快一些。

var [touch, untouch] = (() => {
var seen = new WeakSet();
return [
value => seen.has(value)) || (seen.add(value), !1),
value => !seen.has(value) || (seen.delete(value), !1)
];
})();


function convert(object) {
if(touch(object)) return;
extend(object, yunoprototype); // Made up.
};


function unconvert(object) {
if(untouch(object)) return;
del_props(object, Object.keys(yunoprototype)); // Never do this IRL.
};

由于垃圾回收尚未发生,您的控制台可能错误地显示了内容。因此,由于对象没有被垃圾收集,所以它将显示仍然处于弱集中的对象。

如果您真的想知道某个弱集是否仍然有对某个对象的引用,那么可以使用 WeakSet.prototype.has()方法。顾名思义,此方法返回一个 boolean,指示该对象是否仍然存在于弱集中。

例如:

var weakset = new WeakSet(),
numbers = [1, 2, 3];


weakset.add(numbers);
weakset.add({name: "Charlie"});


console.log(weakset.has(numbers));


numbers = undefined;


console.log(weakset.has(numbers));

当您需要保留一个任意的集合,但是您不希望它们出现在集合中,以防止在内存变得紧张时对这些东西进行垃圾回收时,“弱”集合或映射非常有用。(如果发生垃圾收集 是的,“收获的”对象将从收集中悄悄消失,因此您实际上可以判断它们是否消失了。)

例如,它们非常优秀,可以作为备用缓存使用: “我最近有没有检索过这张唱片?”每次你检索到什么东西,把它放到映射中,知道 JavaScript 垃圾收集器将负责为你“修剪列表”,并且它会自动响应主流的内存条件(这是你无法合理预期的)。

唯一的缺点是这些类型不是“可枚举的”您不能迭代一个条目列表——可能是因为这可能会“触及”这些条目,从而破坏目的。但是,这是一个很小的代价支付(和你 可以,如果需要的话,“代码围绕它”)。

让我回答第一部分,并尽量避免进一步混淆你。

解引用对象的垃圾收集是 无法观察!这将是一个悖论,因为您需要一个对象引用来检查它是否存在于映射中。但别相信我,相信凯尔 · 辛普森: Https://github.com/getify/you-dont-know-js/blob/1st-ed/es6%20%26%20beyond/ch5.md#weakmaps

我在这里看到的许多解释的问题在于,它们将一个变量重新引用到另一个对象,或者为它赋予一个基元值,然后检查 WeakMap 是否包含该对象或值作为键。当然不是!它从未将该对象/值作为键!

因此,这个难题的最后一部分是: 为什么在控制台中检查 WeakMap 仍然会显示那里的所有对象,即使您已经删除了对这些对象的所有引用?因为控制台本身保持对这些对象的持久引用,以便能够列出 WeakMap 中的所有键,因为这是 WeakMap 本身不能做的事情。

在搜索 Weakset 的用例时,我发现了以下几点:

”WeakSet 很弱,这意味着对 WeakSet 中对象的引用保持得很弱。 如果 WeakSet 中存储的对象没有其他引用,那么可以对这些对象进行垃圾收集。”

##################################

它们是黑盒: 只有同时具有 WeakSet 和一个值时,才能从 WeakSet 获得任何数据。

##################################

用例:

1-避免错误

2-它可以是非常有用的,一般来说,避免任何对象被访问/设置两次

参考资料: https://esdiscuss.org/topic/actual-weakset-use-cases

3-WeakSet 的内容可以被垃圾收集。

降低内存利用率的可能性。

参考资料: https://www.geeksforgeeks.org/what-is-the-use-of-a-weakset-object-in-javascript/

##################################

关于弱集的示例: https://exploringjs.com/impatient-js/ch_weaksets.html

我建议你在 JS 中学习更多关于弱概念的知识: < a href = “ https://blog.logrocket.com/sofmap-weaset-understand-javascript-strong-reference/”rel = “ nofollow noReferrer”> https://blog.logrocket.com/weakmap-weakset-understanding-javascript-weak-references/