Javascript 如果我定义了;名称“;具有Object.defineProperty()的属性
我已将代码缩减到最低限度:Javascript 如果我定义了;名称“;具有Object.defineProperty()的属性,javascript,node.js,Javascript,Node.js,我已将代码缩减到最低限度: var util = require('util'); function ErrorDecorator(error) { Error.call(this); this.error = error; } util.inherits(ErrorDecorator, Error); Object.defineProperty(ErrorDecorator.prototype, 'name', { configurable: false,
var util = require('util');
function ErrorDecorator(error) {
Error.call(this);
this.error = error;
}
util.inherits(ErrorDecorator, Error);
Object.defineProperty(ErrorDecorator.prototype, 'name', {
configurable: false,
enumerable: true,
get: function () {
return this.error.name;
}
});
var e = new ErrorDecorator(new Error());
// TypeError: Cannot read property 'name' of undefined
console.log(e.toString());
编辑
我遇到过这样的情况,建议我在构造函数中使用Object.defineProperty
,而不是在原型中使用。我不完全理解为什么,但我只能假设,当我在原型上定义name
时,它被称为“静态的”,而不是以实例作为其上下文
TLDR此代码适用于:
var util = require('util');
function ErrorDecorator(error) {
Error.call(this);
this.error = error;
Object.defineProperty(this, 'name', {
configurable: false,
enumerable: true,
get: function () {
return this.error.name;
}
});
}
util.inherits(ErrorDecorator, Error);
var e = new ErrorDecorator(new Error());
// Error
console.log(e.toString());
编辑2
即使我已经找到了一个解决方案,我仍然有兴趣知道为什么我的第一个代码示例不起作用,以及我所做的是否违背了最佳实践。考虑以下几点:
var x = new Error();
var y = Object.create(x);
y.props = {
name: 42
};
var z = Object.create(y);
Object.defineProperty(y, 'name', {
configurable: false,
enumerable: true,
get: function () {
console.log('Is it Z?', this === z);
console.log('Is it Y?', this === y);
return this.props.name;
}
});
console.log(z.toString());
这很棘手:当对a)没有自己的toString
实现且b)在其原型链中有Error
实例的对象调用toString
时,它遵循所描述的算法:
15.11.4.4 Error.prototype.toString()
采取以下步骤:
- 将
设为O
值此
- 如果
不是类型(O)
,则抛出对象
异常类型错误
- 让
作为使用参数“name”调用name
的[[Get]]
内部方法的结果O
- 如果
是名称
,则名称为“Error”;否则,将name设置为未定义的
ToString(name)
问题在于,由于某种原因,当使用该getter时,nodejs(0.10.33)似乎在原型链上前进了一步:相应地,结果是
false
和true
。Firefox和Chrome都正确地使用z
作为getter上下文。当您调用console.log()
时,您确定e
不是未定义的
?在最后一行设置断点,并在应用程序中断时分析e
。它已定义。这正是我用来重现错误的代码。在另一个控制台之前运行console.log(typeof e)
将显示对象
。仅供参考:console.log(e.name)
将按预期输出错误
。@raina77现在我确信你正确完整地回答了我的问题,但我不明白。你是说toString
被调用了不止一次,而且只有ErrorDecorator
原型调用过一次吗?实际上不是。用console.log('get')
替换get
方法和return 42
只会输出一次。感谢您花时间向我解释这一点。老实说,我一直想问node为什么会这样做,以及它是否在更新的版本中得到了修复——但这太过分了。我很高兴知道,Error.prototype.toString
的NodeJSs实现中可能有一个bug,并且有一个解决方法,可以分别为每个实例定义属性。我使用的是0.10.40版。