简体   繁体   中英

Property accessors vs. Map set method

Is there a way for the following code to either

  1. raise an error on m[k] = v or
  2. make the call m[k] = v automatically translate to m.set(k, v)

I would prefer solution 1. if possible.

// Imagine I write that somewhere
const m = new Map();
m.set("a", "alice");

// And at some point someone else write:
m["b"] = "bob";    // m = Map { 'a' => 'alice', b: 'bob' }
// Expecting "bob" to appear here: 
for (const [k, v] of m){
    console.log(k, v);
}

Note that when I say someone else , this other person could simply be me in the near future. Ideally I would like to have a solution that only modifies the instantiation const m = new Map() . For example to something like const m = safe(new Map()) .

To just prevent properties being added you can use:

 Object.freeze(map);

However, that won't throw an error. To be able to throw an error on a property access you have to use a Proxy, however as that does not work on Maps directly (as they got internal properties that do not get reflected through the Proxy) you'd have to mirror all methods in an object, and use the Proxy on that:

 function safe(map) {
  return new Proxy({
    get(k) { return map.get(k); },
    set(k, v) { return map.set(k, v); }
    // .... others
 }, {
   set() { throw new Error("property setter on Map"); }
 });
}

You could also trap the Proxies getter to directly link to the Map (not sure about side effects though):

function safe(map) {
  return new Proxy({ }, {
   set() { throw new Error("property setter on Map"); },
   get(target, prop, receiver) {
    return typeof map[prop] === "function" ? map[prop].bind(map) : map[prop];
   }
  });
}

you can use proxy

 let m = new Map(); m["a"] = "alice"; m = new Proxy(m, { set(target, name, receiver) { throw "Setting values is forbidden!"; } }); console.log(m["a"]); // you can read value m["b"] = "bob"; // setting value will throw exception

You can use the Proxy object. Instantiate it with the first argument being an instantiation of whatever Map you want.

const m = new Proxy(new Map(), {
    get(target, name, receiver) {
        return target.get(name);
    },
    set(target, name, receiver) {
        // 1. Comment in to allow error to be thrown.
        // throw new Error(`Cannot set property for ${name}`);

        // 2. Comment in to allow setting via bracket syntax.
        // target.set(name, receiver);
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM