ECMAScript 6: what is WeakSet for?

后端 未结 7 717
北荒
北荒 2020-11-29 22:20

The WeakSet is supposed to store elements by weak reference. That is, if an object is not referenced by anything else, it should be cleaned from the WeakSet.

I have

7条回答
  •  时光说笑
    2020-11-29 22:39

    This is a really hard question. To be completely honest I had no idea in the context of JavaScript so I asked in esdiscuss and got a convincing answer from Domenic.

    WeakSets are useful for security and validation reasons. If you want to be able to isolate a piece of JavaScript. They allow you to tag an object to indicate it belongs to a special set of object.

    Let's say I have a class ApiRequest:

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

    Now, I'm writing a JavaScript platform - my platform allows you to run JavaScript to make calls - to make those calls you need a ApiRequest - I only want you to make ApiRequests with the objects I give you so you can't bypass any constraints I have in place.

    However, at the moment nothing is stopping you from doing:

    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
    

    And so on, note that you can't keep a normal list or array of ApiRequest objects since that would prevent them from being garbage collected. Other than a closure, anything can be achieved with public methods like Object.getOwnPropertyNames or Object.getOwnSymbols. So you one up me and do:

    const requests = new WeakSet();
    class ApiRequest {
      constructor() {
        requests.add(this);
      }
    
      makeRequest() {
        if(!request.has(this)) throw new Error("Invalid access");
        // do work
      }
    }
    

    Now, no matter what I do - I must hold a valid ApiRequest object to call the makeRequest method on it. This is impossible without a WeakMap/WeakSet.

    So in short - WeakMaps are useful for writing platforms in JavaScript. Normally this sort of validation is done on the C++ side but adding these features will enable moving and making things in JavaScript.

    (Of course, everything a WeakSet does a WeakMap that maps values to true can also do, but that's true for any map/set construct)

    (Like Bergi's answer suggests, there is never a reason to add an object literal directly to a WeakMap or a WeakSet)

提交回复
热议问题