简体   繁体   中英

TypeError in Node REPL: Cannot read property '0' of undefined when I add a property to the Object.prototype

When I added the name property to Object.prototype and reference Object.prototype , I get the following error:

TypeError: Cannot read property '0' of undefined"

But I can read Object.prototype.name . Is the name property something special for Object.prototype ? Why does this error occur?

The code has been executed in Node v6.9.5 environment on Mac OS X. Does anyone know how to solve this?

$ node
> Object.prototype
{}
> Object.prototype.value = 'foo';
'foo'
> Object.prototype.name = 'bar';
'bar'
> Object.prototype
TypeError: Cannot read property '0' of undefined
> Object.prototype.name
'bar'
> Object.prototype.value
'foo'
> delete Object.prototype.name
true
> Object.prototype
{ value: 'foo' }
> Object.prototype.name = 'bar';
'bar'
> Object.prototype
TypeError: Cannot read property '0' of undefined
> delete Object.prototype.value;
true
> Object.prototype
TypeError: Cannot read property '0' of undefined
    at Object.stylizeWithColor [as stylize] (util.js:242:43)
    at formatProperty (util.js:814:18)
    at util.js:654:12
    at Array.map (native)
    at formatObject (util.js:653:15)
    at formatValue (util.js:592:16)
    at Object.inspect (util.js:186:10)
    at REPLServer.self.writer (repl.js:468:19)
    at finish (repl.js:593:38)
    at REPLServer.defaultEval (repl.js:385:5)

After some inspection I found the culprit and yes, the problem is that "name" is used in a special way.

This error has nothing to do with JavaScript, it is a bug in the Node REPL code that styles the output.

Since we're printing an object, the code ends up executing this function :

function formatObject(ctx, value, recurseTimes, visibleKeys, keys) {
  return keys.map(function(key) {
    return formatProperty(ctx, value, recurseTimes, visibleKeys, key, false);
  });
}

Where value is our Object.prototype , ie { name: 'bar' } and keys is an array of single element, ie ["name"] .

For this single key "name" , execution continues to formatProperty , where it skips the checks to format objects with getters/setters or symbols and reaches a call to formatValue on this line . This call returns a color-coded representation of the value we should print, in our case something like "[32m'bar'[39m" .

Next, the code tries to build a string to display the context being printed. This is the string corresponding to the type of the data being printed, for example [Object] , [Getter] , etc. The execution reaches this call :

ctx.stylize(name, 'name');

The first argument name is our property "name" and the second argument 'name' represents the type of the data we are printing, 'name' meaning variable name.

Further, stylize is actually stylizeWithColor since ctx.colors is true by default.

The error happens in stylizeWithColor on this line .

function stylizeWithColor(str, styleType) {
  var style = inspect.styles[styleType];

  if (style) {
    return `\u001b[${inspect.colors[style][0]}m${str}` + // <- ERROR: `inspect.colors[style][0]` becomes `undefined[0]`
           `\u001b[${inspect.colors[style][1]}m`;
  } else {
    return str;
  }
}

But why?

Well, the call to stylizeWithColor passes 'name' as the styleType , but the only valid values for styleType are:

boolean
date
null
number
regexp
special
string
symbol
undefined

'name' style type is actually ignored as variable names are meant to be unstyled.

These style types are stored in a plain object inspect.styles so the execution expects inspect.styles['name'] on the first line to return undefined (since it is ignored) and not enter the if statement.

// ...

var style = inspect.styles[styleType]; // <-- this should return `undefined`

if (style) { // <-- this shouldn't happen

// ...

However, since inspect.styles is just a POJO and we added a "name" property on Object.prototype , inspect.styles['name'] doesn't find 'name' directly but does find it up the [[Prototype]] chain and actually returns "bar" .

// ...

var style = inspect.styles[styleType]; // <-- this returns "bar"` because it found it up the [[Prototype]] chain

if (style) { // <-- this happens because "bar" is truthy

// ...

This means that the code tries to execute inspect.colors["bar"][0] , where inspect.colors is another POJO containing a mapping of colors to their escaped code values for printing in the terminal. As one would inspect, "bar" is not one of them.

Hence we get undefined[0] , which throws the error in question.

As a matter of fact, if you make name equal to a color value used in inspect.colors , then the error wouldn't happen and the property name will be printed in that color.

节点彩色打印


Edit: I opened a pull request that fixes this problem by making inspect.styles a prototype-less object.

Edit 2: This has been fixed as of Node 8

您应该尝试这样:

  Object.getOwnPropertyNames(Object);

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