Skip to content

console.log(proxy) invokes get trap with built-in Symbols #10731

Closed
@zbjornson

Description

@zbjornson
  • Version: v6.9.2 and v7.4.0
  • Platform: Ubuntu 16.06 LTS
  • Subsystem: console, util

Calling console.log (util.inspect with default opts) on an instance of a Proxy invokes the get trap with some built-in Symbols. (It also invokes the trap with "inspect" and "valueOf", which is different than browser behavior but doesn't seem as problematic.)

In node:

> var p = new Proxy({a: 1}, {get(o, p) { console.log(typeof p, p); }}); console.log(p)
symbol Symbol(util.inspect.custom)
string inspect
string valueOf
symbol Symbol(Symbol.toStringTag)
{ a: 1 }

In chrome:

> var p = new Proxy({a: 1}, {get(o, p) { console.log(typeof p, p); }}); console.log(p)
Proxy {a: 1}

In FF:

> var p = new Proxy({a: 1}, {get(o, p) { console.log(typeof p, p); }}); console.log(p)
Proxy { <target>: Object, <handler>: Object }

In Edge:

MSEdge output
var p = new Proxy({a: 1}, {get(o, p) { console.log(typeof p, p); }}); console.log(p)
undefined
string toString
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string __defineGetter__
eval code (7) (1,40)
string __defineSetter__
eval code (7) (1,40)
string __lookupGetter__
eval code (7) (1,40)
string __lookupSetter__
eval code (7) (1,40)
string __proto__
eval code (7) (1,40)
string a
eval code (7) (1,40)
string constructor
eval code (7) (1,40)
string hasOwnProperty
eval code (7) (1,40)
string isPrototypeOf
eval code (7) (1,40)
string propertyIsEnumerable
eval code (7) (1,40)
string toLocaleString
eval code (7) (1,40)
string toString
eval code (7) (1,40)
string valueOf
eval code (7) (1,40)
string toString
eval code (7) (1,40)
[object Object]
eval code (7) (1,71)
   {
      __defineGetter__: undefined,
      __defineSetter__: undefined,
      __lookupGetter__: undefined,
      __lookupSetter__: undefined,
      __proto__: undefined,
      a: undefined,
      constructor: undefined,
      hasOwnProperty: undefined,
      isPrototypeOf: undefined,
      propertyIsEnumerable: undefined,
      toLocaleString: undefined,
      toString: undefined,
      valueOf: undefined
   }

If you're expecting your object to have Symbol keys and thus handle them, that's fine, but if you're only using string keys, then this can make it necessary to add a guard clause like if (typeof p !== "string") return o[p]; within the get trap. None of the above three browsers invoke the trap with a Symbol, by comparison.

The showProxy: true option for util.inspect prevents these four calls and making it the default could be a fix, but from the comments in #6465 it is apparently too slow. However, a simple isProxy binding (args.GetReturnValue().Set(args[0]->IsProxy())) is 10x faster than the getProxyDetails binding (29 ms vs 280 ms for 1M ops), and the target can be inspected the same as a plain object (without the binding). It seems like there's some special casing that could be done cheaply to avoid invoking the get trap with symbols, or even invoking it at all.

Maybe this is a wontfix -- maybe it's only sane if symbols are handled -- but right now this seems like an addition required to make some get traps compatible with node.

Metadata

Metadata

Assignees

No one assigned

    Labels

    utilIssues and PRs related to the built-in util module.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions