节点REPL中的TypeError:当我向Object.prototype添加属性时,无法读取未定义的属性“0”
当我将name
属性添加到Object.prototype
并引用Object.prototype
,出现以下错误:
TypeError: Cannot read property '0' of undefined"
但是我可以读取Object.prototype.name
。 Object.prototype
的name
属性是否特殊? 为什么会发生这种错误?
该代码已在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]
,这引发了有问题的错误。
事实上,如果您的name
与inspect.colors
使用的颜色值inspect.colors
,则错误不会发生,属性name
将以该颜色打印。
编辑:我打开一个pull请求 ,通过使inspect.styles
一个无原型对象来解决这个问题。
你应该试试这个:
Object.getOwnPropertyNames(Object);