Javascript 创建自定义错误:理解MDN示例

Javascript 创建自定义错误:理解MDN示例,javascript,error-handling,Javascript,Error Handling,关于如何在JS中创建自定义错误的以下示例可以在MDN()上找到 我正在努力理解发生了什么(具体问题如下) 函数自定义错误(foo、消息、文件名、行号){ var实例=新错误(消息、文件名、行号); instance.foo=foo; setPrototypeOf(实例,Object.getPrototypeOf(this)); if(Error.captureStackTrace){ 错误。captureStackTrace(实例,CustomError); } 返回实例; } CustomE

关于如何在JS中创建自定义错误的以下示例可以在MDN()上找到

我正在努力理解发生了什么(具体问题如下)

函数自定义错误(foo、消息、文件名、行号){
var实例=新错误(消息、文件名、行号);
instance.foo=foo;
setPrototypeOf(实例,Object.getPrototypeOf(this));
if(Error.captureStackTrace){
错误。captureStackTrace(实例,CustomError);
}
返回实例;
}
CustomError.prototype=Object.create(Error.prototype{
建造商:{
值:错误,
可枚举:false,
可写:对,
可配置:true
}
});
if(Object.setPrototypeOf){
setPrototypeOf(CustomError,Error);
}否则{
CustomError.\uuuu proto\uuuu=错误;
}
试一试{
抛出新的CustomError('baz','bazMessage');
}捕获(e){
console.log(e.foo);//baz
console.log(e.message);//消息
}
  • 当使用
    CustomError
    作为正常功能时,
    的值在其内部是
    未定义的
    。但如果将其用作构造函数
    ,则该
    将引用当前实例。考虑到
    被传递到
    getPrototypeOf
    ,将其作为普通函数调用将抛出错误并中断代码。但如果
    CustomError
    按如下方式执行,则情况相同:

    function CustomError(){
        if(!(this instanceof MyError)) return new CustomError();
    }
    
  • 那和你想的一模一样

  • 我不知道为什么您认为它不能用作构造函数,因为它已经在
    try/catch
    语句中用
    new
    关键字调用了

  • 在第4行
    实例中
    的原型设置为
    的原型
    引用了
    CustomError
    的当前实例,因为它是通过
    new
    调用的

  • 由于并非所有环境都支持
    Error.captureStackTrace
    (仅限afaik chrome和nodejs支持),因此它会在使用该函数之前检查该函数是否存在


  • 编辑部分

    • 每当我们使用构造函数(new关键字)创建一个新对象时,它就会将prototype链接到
      Person.prototype
      (至少具有
      constructor
      属性),而prototype又链接到object.prototype

    • prototype链接到
      个人。prototype
      ,因为
      个人
      构造函数创建了它,而构造函数将新创建的对象链接到他们自己的prototype对象。是的,您可以更改
      Person.prototype
      ,而不影响
      Object.prototype

      • Error()
        是一只野兽。 当调用它的构造函数时,它只会忽略
        这个
        ,并创建一个新的错误对象。 通常,在初始化自己的修改之前,可以使用
        Error.call(this,…)
        为其超类初始化新的子类实例。但是,如果出现错误,这将失败,因为您将返回一个初始化的新错误对象,而实际实例保持不变。Error()只会忽略它的
        this
        ,并始终创建一个新实例。 为了避免这种情况,必须创建一个新的错误,然后需要将其原型更改为自定义原型(从Error.prototype派生),并返回此实例,丢弃由初始新创建的实例,就像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
        (就像
        Error
        )实例化MyError

        但有一个问题:
        所有现存的错误类型实际上都是同一错误类的实例,而不是错误的子类。至少在铬上。另外,有些函数是Error的一部分,而不是Error.prototype的一部分,因此它们在类中不可用(如captureStackTrace)。如果你克隆它们,可能会有用。

        第二个列表中的第四个和第五个是真的,但我无法理解你在第三个列表中的意思。谢谢Hikmat,我会花一些时间消化你写的内容,然后跟进任何问题。关于你的“编辑部分”,是的,我完全理解你。我只是想强调另外一个事实,构造函数
        Male
        Female
        可能都使用
        Person.prototype
        作为它们的原型对象,但因为我们将
        Male.prototype
        Female.prototype
        设置为链接到
        Person.prototype
        的空对象prototype(使用
        Create.object()
        ),而不是直接将其设置为
        Person.prototype
        ,我们确保可以将原型更改为
        Male
        ,而不会影响
        Male
        。我认为,如果我们在构造函数中返回一个对象,那么使用
        this
        引用新创建的对象都会被忽略(即构造函数的工作方式与普通函数相同).这是错误的理解吗?如果您使用
        new
        kewword调用函数,则该函数可以访问
        this
        ,而不管函数内部发生了什么。Hikmat,我已经对此进行了一些研究,似乎如果我们从构造函数返回对象,它就不再像您期望的构造函数那样工作了tor函数开始工作。与任何其他函数一样,它不会将
        this
        分配给新对象,然后返回它,而是从
        return
        语句返回对象。请参见:,以及:this: