Skip to content

Proxies: console.log uses overridden proxy methods by default #12453

Description

@ace-n

Version: 8.0.0-pre
Platform: Darwin MACHINE_NAME.local 14.3.0 Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64 x86_64

The following code sample throws an error, due to console.log using the proxy's overridden get - is it supposed to? (FWIW, Chrome's v8 does not throw an error and instead logs the target of the Proxy.)

'use strict';

const handler = {
    get: function(target, prop) {
      throw new Error('whoops');
    }
};
const sandbox = new Proxy({foo: 'bar'}, handler);
console.log(sandbox);
/Users/ace/Desktop/node/test.js:5
      throw new Error('whoops');
      ^

Error: whoops
    at Object.get (/Users/ace/Desktop/node/test.js:5:13)
    at formatValue (util.js:311:38)
    at inspect (util.js:152:10)
    at exports.format (util.js:34:24)
    at Console.log (console.js:85:24)
    at Object.<anonymous> (/Users/ace/Desktop/node/test.js:9:9)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)

Activity

  1. added
    utilIssues and PRs related to the built-in util module.
    on Apr 16, 2017
  2. addaleax commented on Apr 16, 2017

    @addaleax
    Member

    Just fyi, util.inspect (and console.dir indirectly too) has a showProxy option that lets you enable displaying the proxy itself, see https://nodejs.org/api/util.html#util_util_inspect_object_options.

    But I see your point, and I’m not sure whether this should be a bug or not myself. What’s the alternative to passing the error along? Just defaulting to displaying the Proxy target doesn’t seem quite right…

  3. ace-n commented on Apr 16, 2017

    @ace-n
    Author

    To be honest, it makes sense to me that console.log should respect the Proxy (and, as you said, pass the error along). But it doesn't seem like it does so universally:

    'use strict';
    
    const handler = {
        get: function(target, prop) {
          return target[prop] + "baz";
        }
    };
    const sandbox = new Proxy({foo: 'bar'}, handler);
    console.log(sandbox);
    console.log(sandbox.foo);
    
    { foo: 'bar' } // should this be { foo: 'barbaz' }?
    barbaz
    

    Perhaps this is a question for the v8 folks?

  4. addaleax commented on Apr 16, 2017

    @addaleax
    Member

    That latter behaviour is because util.inspect uses Object.getOwnPropertyDescriptor to get the value, and in your example the proxy doesn’t provide that trap.

    (Ironically, one of the reasons util.inspect does that is to avoid getters that might throw errors. 😄)

  5. ace-n commented on Apr 16, 2017

    @ace-n
    Author

    Here's an example with the trap added:

    'use strict';
    
    const handler = {
        get: function(target, prop) {
          return (target && target[prop] && typeof target[prop] == 'string') ?
          	target[prop] + "baz" :
          	target[prop];
        },
        getOwnPropertyDescriptor: function(target, prop) {
          let a = Object.getOwnPropertyDescriptor(target, prop);
          if (a)
          	a.value = this.get(target, prop);
          return a;
        }
    };
    const sandbox = new Proxy({foo: 'bar'}, handler);
    console.log(sandbox);
    console.log(sandbox.foo);
    
    { foo: 'barbaz' }
    barbaz
    

    At first glance, it seems like everything is working correctly in this example (that doesn't involve error throwing). Perhaps this is just an eccentricity of Node or even Javascript itself? (I'm not sure if the ECMA specification has anything to say about this.)

  6. TimothyGu commented on Apr 17, 2017

    @TimothyGu
    Member

    There are really no consensus on what console.log should do in this instance.

    The way Chrome handles it is always displaying the proxied target in the short one-line view, and providing more information about the proxy once you expand it:

    image
    image

    Firefox on the other hand always displays the proxied values, and does not allow introspection of the internal slots of the proxy object:

    image

    And in case of thrown errors, it just says "Error":

    image

    FWIW the Console Standard does not say anything about the possibility of throwing either.

  7. Trott commented on Aug 2, 2017

    @Trott
    Member

    Should this remain open?

  8. BridgeAR commented on Aug 28, 2017

    @BridgeAR
    Member

    As far as I see it everything is working as it should. I am closing this therefore.

  9. bnoordhuis commented on Aug 29, 2017

    @bnoordhuis
    Member

    Linking to #13784 - it's related in the sense that we currently lack a safe way to inspect JS values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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