Node REPL中的TypeError:当我向Object.prototype添加属性时,无法读取未定义的属性'0'

时间:2017-02-24 05:31:16

标签: javascript node.js

当我将name属性添加到Object.prototype并引用Object.prototype时,我收到以下错误:

TypeError: Cannot read property '0' of undefined"

但我可以阅读Object.prototype.namename属性对Object.prototype有什么特别之处吗?为什么会出现这种错误?

代码已在Mac OS X上的Node v6.9.5环境中执行。有谁知道如何解决这个问题?

$ 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)

1 个答案:

答案 0 :(得分:5)

经过一番检查后,我找到了罪魁祸首,是的,问题是"name"以特殊方式使用。

此错误与JavaScript无关,它是Node REPL代码中的一个错误,它会对输出进行样式设置。

由于我们正在打印对象,因此代码最终会执行this function

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

valueObject.prototype{ name: 'bar' }keys是单个元素的数组,即["name"]

对于此单个键"name",执行继续到formatProperty,它会跳过检查以使用getter / setter或符号格式化对象,并在{{3}上调用formatValue }}。此调用返回我们应该打印的值的颜色编码表示,在我们的示例中类似"[32m'bar'[39m"

接下来,代码尝试构建一个字符串以显示正在打印的上下文。这是与正在打印的数据类型相对应的字符串,例如[Object][Getter]等。执行this line

ctx.stylize(name, 'name');

第一个参数name是我们的属性"name",第二个参数'name'表示我们正在打印的数据的类型,'name'表示变量名。

此外,stylize实际上是reaches this call,因为默认情况下stylizeWithColor为真。

错误发生在ctx.colors上的stylizeWithColor

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;
  }
}

但为什么?

嗯,stylizeWithColor的来电通过'name'作为styleType,但styleType的唯一有效值是:

boolean
date
null
number
regexp
special
string
symbol
undefined

'name'样式类型实际上是this line,因为变量名称是无格式的。

这些样式类型存储在普通对象ignored中,因此执行期望第一行上的inspect.styles['name']返回undefined(因为它被忽略)而不是输入{{1声明。

if

但是,由于// ... var style = inspect.styles[styleType]; // <-- this should return `undefined` if (style) { // <-- this shouldn't happen // ... 只是一个POJO而我们在inspect.styles上添加了"name"属性,Object.prototype没有直接找到inspect.styles['name']但是确实找到了[[Prototype]]链并实际返回'name'

"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 // ... ,其中inspect.styles是另一个POJO,其中包含颜色到inspect.colors的映射,以便在终端中打印。正如人们所检查的那样,inspect.colors["bar"][0]不是其中之一。

因此我们得到"bar",这会引发有问题的错误。

事实上,如果您使undefined[0]等于name中使用的颜色值,那么错误就不会发生,并且会打印属性inspect.colors那种颜色。

escaped code values

编辑:我打开了node color print,通过使name成为无原型对象来解决此问题。

编辑2:自pull request

起修复此问题