4

I want to use an ES6 proxy to trap the following common code:

for (let key in trapped) {
    if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
    let value = trapped[key];
    //various code
}

But after reviewing the proxy documentation, I'm not sure how to do it, mainly because the has trap trap is for the in operator, which does not seem to be used in the above code and there is no trap for the hasOwnProperty operation.

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
GregRos
  • 8,667
  • 3
  • 37
  • 63

2 Answers2

17

You can use the getOwnPropertyDescriptor handler to capture hasOwnProperty() calls.

Example:

const p = new Proxy({}, {
  getOwnPropertyDescriptor(target, property) {
    if (property === 'a') {
      return {configurable: true, enumerable: true};
    }
  }
});

const hasOwn = Object.prototype.hasOwnProperty;

console.log(hasOwn.call(p, 'a'));
console.log(hasOwn.call(p, 'b'));

This is specified behavior, not a quirk of a particular implementation:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
2

I was actually going to answer my question myself, but I was too slow, and others answered it first (and added very useful information besides). Nevertheless, here is the answer I wanted to write, in case it might help someone somehow:


It appears that the getOwnPropertyDescriptor trap is fired when hasOwnProperty is called. So you can trap hasOwnProperty by doing the following:

getOwnPropertyDescriptor(target, name) {
    return {
        value : target[name],
        //use a logical set of descriptors:
        enumerable : true,
        configurable : true,
        writable : true
    };
}

The other part is trapping get and ownKeys as well:

get(target, name) {
    return {}; //replace this with a relevant object
}

//These will be iterated over as part of the for loop
ownKeys() {
    return ["RelevantProperty1", "RelevantProperty2"];
}

All in all, since you have to return an array of properties when you trap ownKeys, using a proxy doesn't seem to make things much better in this use case. I think for the majority of situations, the following would work just as well and be less fragile:

let obj = {};
let keys = ["a" , "b"];
for (let key of keys) {
    obj[key] = {}; //relevant object
}

So using a proxy might be overkill.

GregRos
  • 8,667
  • 3
  • 37
  • 63
  • 1
    It's usually better to prepare the answer before posting the question, so you can post them at once. Saves on these sort of situations happening. Still, useful nonetheless. – VLAZ Nov 06 '16 at 16:53
  • @vlaz that's a good point. I'll remember it in the future. Still, I'm glad Gothdo and others elaborated on how the mechanism works. – GregRos Nov 06 '16 at 23:59