出于某种原因,在下面的代码段中,构造函数委托似乎不起作用:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

运行该命令得到的消息是:"。有什么想法,为什么,或者是否有更好的方法来创建一个新的错误子类?是否有一个问题,应用到本机错误构造函数,我不知道?


当前回答

这部分的标准可以解释为什么错误。Apply调用不会初始化对象:

15.11.1错误构造函数作为函数调用 当Error作为函数而不是构造函数调用时,它会创建和 初始化一个新的Error对象。因此函数调用Error(…)是 等价于对象创建表达式new Error(… 相同的参数。

在这种情况下,Error函数可能确定它没有作为构造函数被调用,因此它返回一个新的Error实例,而不是初始化this对象。

用下面的代码进行测试似乎证明了这就是实际发生的情况:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

运行此命令时输出如下:

returned.message = 'some message'
this.message = ''

其他回答

这部分的标准可以解释为什么错误。Apply调用不会初始化对象:

15.11.1错误构造函数作为函数调用 当Error作为函数而不是构造函数调用时,它会创建和 初始化一个新的Error对象。因此函数调用Error(…)是 等价于对象创建表达式new Error(… 相同的参数。

在这种情况下,Error函数可能确定它没有作为构造函数被调用,因此它返回一个新的Error实例,而不是初始化this对象。

用下面的代码进行测试似乎证明了这就是实际发生的情况:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

运行此命令时输出如下:

returned.message = 'some message'
this.message = ''

如果你使用Node/Chrome。下面的代码片段将为您提供满足以下要求的扩展。

err instanceof Error err instanceof CustomErrorType console.log() returns [CustomErrorType] when created with a message console.log() returns [CustomErrorType: message] when created without a message throw/stack provides the information at the point the error was created. Works optimally in Node.JS, and Chrome. Will pass instanceof checks in Chrome, Safari, Firefox and IE 8+, but will not have a valid stack outside of Chrome/Safari. I'm OK with that because I can debug in chrome, but code which requires specific error types will still function cross browser. If you need Node only you can easily remove the if statements and you're good to go.

片段

var CustomErrorType = function(message) {
    if (Object.defineProperty) {
        Object.defineProperty(this, "message", {
            value : message || "",
            enumerable : false
        });
    } else {
        this.message = message;
    }

    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, CustomErrorType);
    }
}

CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";

使用

var err = new CustomErrorType("foo");

输出

var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);

[CustomErrorType: foo]
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

/errorTest.js:30
        throw err;
              ^
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

这是最快的方法:

    let thisVar = false

    if (thisVar === false) {
            throw new Error("thisVar is false. It should be true.")
    }

以上所有的答案都很糟糕,真的。即使是107个向上的那个!真正的答案在这里:

从Error对象继承- message属性在哪里?

TL; diana:

a .没有设置message的原因是Error是一个函数,它返回一个新的Error对象,并且不以任何方式操作它。

B.正确的方法是从构造函数返回apply的结果,以及以通常复杂的javascript方式设置原型:

function MyError() { var temp = Error.apply(this, arguments); temp.name = this.name = 'MyError'; this.message = temp.message; if(Object.defineProperty) { // getter for more optimizy goodness /*this.stack = */Object.defineProperty(this, 'stack', { get: function() { return temp.stack }, configurable: true // so you can change it if you want }) } else { this.stack = temp.stack } } //inherit prototype using ECMAScript 5 (IE 9+) MyError.prototype = Object.create(Error.prototype, { constructor: { value: MyError, writable: true, configurable: true } }); var myError = new MyError("message"); console.log("The message is: '" + myError.message + "'"); // The message is: 'message' console.log(myError instanceof Error); // true console.log(myError instanceof MyError); // true console.log(myError.toString()); // MyError: message console.log(myError.stack); // MyError: message \n // <stack trace ...> //for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code: /* var IntermediateInheritor = function() {}; IntermediateInheritor.prototype = Error.prototype; MyError.prototype = new IntermediateInheritor(); */

您可能会使用一些技巧来枚举tmp Error的所有不可枚举属性来设置它们,而不是显式地只设置stack和message,但是ie<9不支持这种技巧

这在Cesium DeveloperError中很好地实现了:

文档 源

它的简化形式是:

var NotImplementedError = function(message) {
    this.name = 'NotImplementedError';
    this.message = message;
    this.stack = (new Error()).stack;
}

// Later on...

throw new NotImplementedError();