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

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

 TypeError: Cannot read property '0' of undefined" 

但是我可以读取Object.prototype.nameObject.prototypename属性是否特殊? 为什么会发生这种错误?

该代码已在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) 

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

这个错误与JavaScript没有任何关系,它是Node REPL代码中输出样式的错误。

由于我们正在打印一个对象,代码最终执行这个函数 :

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

其中value是我们的Object.prototype ,即{ name: 'bar' }keys是一个单一元素的数组,即["name"]

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

接下来,代码尝试构build一个string来显示正在打印的上下文。 这是与正在打印的数据types相对应的string,例如[Object][Getter]等。执行达到此调用 :

 ctx.stylize(name, 'name'); 

第一个参数name是我们的属性"name" ,第二个参数'name'表示我们正在打印的数据的types, 'name'表示variables名称。

此外, stylizeWithColor实际上是stylizeWithColor因为ctx.colors默认为true。

这行错误发生在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'风格types实际上被忽略,因为variables名称是未被devise的。

这些样式types存储在一个普通对象inspect.styles所以执行期望在第一行的inspect.styles['name']返回undefined (因为它被忽略)而不是inputif语句。

 // ... var style = inspect.styles[styleType]; // <-- this should return `undefined` if (style) { // <-- this shouldn't happen // ... 

但是,由于inspect.styles只是一个POJO,我们在Object.prototype上添加了一个"name"属性, inspect.styles['name']没有直接find'name' ,而是find[[Prototype]]链,实际上返回"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.colors["bar"][0] ,其中inspect.colors是另一个POJO,其中包含颜色映射到其转义代码值以便在terminal中打印。 正如人们所看到的, "bar"不是其中之一。

因此,我们得到undefined[0] ,这引发了有问题的错误。

事实上,如果您的nameinspect.colors使用的颜色值inspect.colors ,则错误不会发生,属性name将以该颜色打印。

节点彩色打印


编辑:我打开一个pull请求 ,通过使inspect.styles一个无原型对象来解决这个问题。

你应该试试这个:

  Object.getOwnPropertyNames(Object);