以下有关如何在JS中创建自定义错误的示例可以在MDN(link)上找到。
我正在努力了解正在发生的事情(下面的特定问题)。
function CustomError(foo, message, fileName, lineNumber) {
var instance = new Error(message, fileName, lineNumber);
instance.foo = foo;
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
if (Error.captureStackTrace) {
Error.captureStackTrace(instance, CustomError);
}
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
if (Object.setPrototypeOf) {
Object.setPrototypeOf(CustomError, Error);
} else {
CustomError.__proto__ = Error;
}
try {
throw new CustomError('baz', 'bazMessage');
} catch (e) {
console.log(e.foo); //baz
console.log(e.message); //bazMessage
}
问题
CustomError
内部的对象,因此将其用作构造函数函数(new CustomError()
),并将其用作普通函数对象({{1} })产生相同的结果?CustomError()
设置为CustomError.prototype
,以便我们可以扩展原型而不会影响所有其他Error.prototype
对象? / li>
Error
属性呢?prototype
Error
设置为所谓的函数,对吗?我不明白目的是什么/ instance
的值是什么。this
检查的目的是什么?感谢您帮助我分析和理解此代码段。
我想补充一点,我想我已经了解以下内容:
captureStackTrace
关键字)创建新对象时,它都会原型链接到一个空对象,而空对象又将原型链接到{{1} } new
的原型,因为这样我们可以扩展新对象的原型,而无需更改Object.prototype
上的所有对象的行为它的原型链。Object.prototype
属性,则它应该反映相同的行为。实际上,我们应该将Object.prototype
属性设置为一个空对象,而该对象又是链接到我们新引入的“父级”的原型示例:
prototype
prototype
属性时,我们不仅应将新的空对象分配给function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Male(name) {
Person.call(this, name, "male");
}
Male.prototype = Object.create(Person.prototype, {
constructor: {
value: Male,
enumerable: false,
writeable: true
}
});
var person1 = new Male("Chris");
属性,还应设置该空对象的prototype
属性prototype
的行为,其中constructor
属性为Object.prototype
(与其他内置函数相同)这应该解释第二个块。我正确理解了那部分吗?
答案 0 :(得分:1)
将CustomError
用作常规函数时,this
的值位于其中undefined
处。但是,如果将其用作构造函数,则this
将引用当前实例。考虑到this
被传递给getPrototypeOf
,将其作为普通函数调用将引发错误并破坏代码。但是,如果CustomError
的实施方式如下所示,将是相同的:
function CustomError(){
if(!(this instanceof MyError)) return new CustomError();
}
那完全像你的想法
我不确定您为什么认为它不能用作构造函数,因为它已经在new
语句中用try/catch
关键字进行了调用
在第4行中,instance
的原型设置为this
的原型。 this
指的是CustomError
的当前实例,因为它是通过new
调用的。
由于并非所有环境都支持Error.captureStackTrace
(仅afaik chrome和nodejs支持它),因此它会在使用该功能之前检查该功能是否存在。
编辑零件
每当我们使用构造函数(新关键字)创建新对象时,它都会原型链接到 Person.prototype
(至少具有consctructor
属性) ,这是链接到Object.prototype的原型
它是链接到 Person.prototype
的原型,因为Person
构造函数创建了它,构造函数将新创建的对象链接到他们自己的原型对象。是的,您可以更改Person.prototype
而不会影响Object.prototype
。
答案 1 :(得分:1)
Error()
是野兽。
调用其构造函数时,它仅忽略this
并创建一个新的Error对象。
通常,在初始化自己的修改之前,可以使用Error.call(this,...)
为其超类初始化新的子类实例。但是,使用Error,这将失败,因为您将返回初始化的新Error对象,并且实际实例保持不变。 Error()只是忽略其this
并始终创建一个新实例。
为了避免这种情况,必须创建一个新的Error,然后将其原型更改为自定义原型(从Error.prototype派生),然后返回此实例,丢弃由最初的新对象创建的实例,例如Error这样做(因此我们必须在所有子类中复制Error的这种不良行为)。
以下作品:
MyErrorr = function() { // Class MyError
var prototype = Object.create (Error.prototype, { name: {writable: false, enumerable: true, value: "MyError"}});
function MyError (reason, callee) {
if(reason instanceof MyError)
return new MyError(reason.message); // clone
// creating an Error is a bit tricky, as Error.call(this, message) behaves like new Error(message), creating a new instance
var instance = new Error(reason);
if(Error.captureStackTrace)
Error.captureStackTrace(instance, callee?callee:MyError); // exclude the callee or at least MyError() from the stack trace
var stack = instance.stack; // force creation of the stack output before the prototype is switched (else the formatting is different, no idea why)
if(Object.setPrototypeOf)
Object.setPrototypeOf(instance, prototype);
else
instance.__proto__ = prototype;
return instance;
};
prototype.constructor = ConversionError;
MyError.prototype = prototype;
return MyError;
}();
由于未使用'this',因此可以使用和不使用new
来实例化MyError(就像Error
一样)
但是有一个问题: 所有这些存在的Error类型实际上是同一Error类的实例,而不是Error的子类。至少在Chrome上。另外,某些函数是Error的一部分,而不是Error.prototype的一部分,因此它们在您的类中不可用(例如captureStackTrace)。如果您将它们克隆,也许可以使用。