Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Object.keys() and Object.getOwnPropertyNames() produce different output when called on a Proxy object with ownKeys handler?

I have the following proxy:

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
});

MDN says that:

This trap can intercept these operations:

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • Reflect.ownKeys()

Therefore, I expected Object.getOwnPropertyNames() and Object.keys() to produce the same output. However, Object.getOwnPropertyNames(p) returns ['a', 'b'] (as expected), but Object.keys(p) returns an empty array. Why is that?

Also, if I add a property to this object which is not returned by the ownKeys handler (for example c), it gets ignored by both functions (they don't change their output). However, when I add a property which is returned by the ownKeys handler (for example a), Object.keys(p) now returns ['a'].

Code snippet:

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
});

console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // []

p.c = true;
console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // []

p.a = true;
console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // ['a']
like image 788
Michał Perłakowski Avatar asked Nov 01 '16 00:11

Michał Perłakowski


People also ask

What is the difference between object keys and object getOwnPropertyNames?

getOwnPropertyNames(a) returns all own properties of the object a . Object. keys(a) returns all enumerable own properties. It means that if you define your object properties without making some of them enumerable: false these two methods will give you the same result.

Which object does a proxy object need to manage the call of the intercepted method?

target : the original object which you want to proxy. handler : an object that defines which operations will be intercepted and how to redefine intercepted operations.

What does a proxy do to the target object?

A Proxy is a placeholder object that “traps” invocations and operations made to its target object which it can then passthrough, no-op, or handle more elegantly. It creates an undetectable barrier around the target object that redirects all operations to the handler object.

What is object getOwnPropertyNames?

Object. getOwnPropertyNames() returns an array whose elements are strings corresponding to the enumerable and non-enumerable properties found directly in a given object obj . The ordering of the enumerable properties in the array is consistent with the ordering exposed by a for...in loop (or by Object.


2 Answers

The difference between Object.keys() and Object.getOwnPropertyNames() is that Object.keys() will invoke [[GetOwnProperty]] on the object, and only add the property to the result list if the returned property descriptor is enumerable. Since the object doesn't have a such a property, [[GetOwnProperty]] will return undefined and the property (name) is ignored.

You can overwrite/implement [[GetOwnProperty]] in the proxy by implementing getOwnPropertyDescriptor:

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
  getOwnPropertyDescriptor(k) {
    return {
      enumerable: true,
      configurable: true,
    };
  }
});

console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // ['a', 'b']
like image 102
Felix Kling Avatar answered Sep 23 '22 03:09

Felix Kling


The difference between Object.keys and Object.getOwnPropertyNames is that the latter returns own properties regardless of whether or not they are enumerable.

The properties added to the object by Proxy are non-enumerable, and won't show up in Object.keys, but will in Object.getOwnPropertyNames

Generally, properties added by assignment or a property initializer are enumerable by default, and properties added with methods such as Object.assign, new Proxy etc. are non-enumerable by default.

There's more on property ownership and enumerability on MDN, where one can also find this table that outlines the difference in the two methods

enter image description here

like image 32
adeneo Avatar answered Sep 25 '22 03:09

adeneo