正确的非字符串Javascript异常

正确的非字符串Javascript异常,javascript,exception,exception-handling,ecmascript-5,Javascript,Exception,Exception Handling,Ecmascript 5,不知何故,这并不像是50年编程语言发展的顶峰: throw "My exception message here"; 在Javascript中执行异常的正确方法是什么 它们可以被识别(instanceof) 除了默认消息和堆栈跟踪之外,它们还可以携带其他有效负载 它们“子类化”基本异常,以便调试控制台等可以提取有关异常的有意义信息 可能的嵌套异常(将异常转换为另一个异常):如果需要捕获异常并重新生成新异常,则原始堆栈跟踪将被保留,并可由调试工具进行有意义的读取 它们遵循Javascrip

不知何故,这并不像是50年编程语言发展的顶峰:

  throw "My exception message here";
在Javascript中执行异常的正确方法是什么

  • 它们可以被识别(instanceof)

  • 除了默认消息和堆栈跟踪之外,它们还可以携带其他有效负载

  • 它们“子类化”基本异常,以便调试控制台等可以提取有关异常的有意义信息

  • 可能的嵌套异常(将异常转换为另一个异常):如果需要捕获异常并重新生成新异常,则原始堆栈跟踪将被保留,并可由调试工具进行有意义的读取

  • 它们遵循Javascript最佳实践

    • JavaScript中的基本“异常”是内置的
      错误
      对象:

      throw new Error("My exception message here");
      
      您可以将自定义异常定义为:

      function CustomError(message) {
        this.message = message;
      }
      
      CustomError.prototype = new Error();
      CustomError.prototype.constructor = CustomError;
      

      使用
      instanceof
      检查异常类型。还有一个。

      您可以通过调用。
      错误
      对象可以有消息和名称。捕获时,您可以检查特定名称,也可以通过继承
      错误
      原型来创建自定义错误类型。这使得不同错误类型之间的
      instanceof
      的使用有所不同

      // Create a new object, that prototypally inherits from the Error constructor.  
      function MyError(message) {  
          this.message = message || "Default Message";  
      }  
      MyError.prototype = new Error();  
      MyError.prototype.constructor = MyError;  
      
      try {  
          throw new MyError();  
      } catch (e) {  
          console.log(e.name);     // "MyError"  
          console.log(e.message);  // "Default Message"  
      }  
      
      try {  
          throw new MyError("custom message");  
      } catch (e) {  
          console.log(e.name);     // "MyError"  
          console.log(e.message);  // "custom message"  
      }  
      
      示例取自:

      抛出新错误(“消息”)

      或者,如果您想更具体地使用

      确保抛出真正的错误很重要,因为它们包含堆栈跟踪。抛出字符串是愚蠢的,因为它没有附加任何元数据

      您还可以对错误进行子类化

      // for some sensible implementation of extend 
      // https://gist.github.com/1441105#file_1pd.js
      var MyError = extend(Object.create(Error.prototype), {
         ...
      });
      

      你不能这样做,并满足问题的要求

      为什么?

      问题是获取堆栈。本机错误对象(从现在起为NativeError)在调用其构造函数时初始化堆栈。要在MyError(错误子类)中获取堆栈,必须在MyError的构造函数中调用NativeConstructor。因此,您的MyError类如下所示:

      function MyError(msg) {
          Error.call(this, msg);
      }
      
      但是,这是行不通的。因为根据规范:

      “如果您将Error作为函数调用,它将返回一个新的Error对象”

      它创建了一个您不需要的错误对象,而不是很好地初始化您的自定义错误类。我还没有找到调用NativeError构造函数并让它初始化MyError子类的方法

      并不是所有的东西都丢了

      如果我们放松了最初的问题要求,忘记了“instanceof”来测试异常类(不管怎样,Java也是如此),而是使用“name”,那么就可以完成。只需将MyError声明为:

      function MyError(msg, customArg) {
          var e = new Error(msg);
          e.name = "MyError";
          e.custom = customArg;
          return e;
      }
      


      我就是这么做的。不要打开“instanceof”,而是打开“name”。

      JavaScript真的没有这些吗?你能在JS中将任何对象序列化为字符串吗?@VladislavZorov:是的,Javascript有这些。在问题的开头阐明了嵌套异常的必要性。任何关于JavaScript的讨论都应该这样开始偏好
      x.prototype=Object.create(y.prototype)
      @Raynos在浏览器环境中
      Object.create
      可能不可用,您需要一个polyfill。在JavaScript>=1.8.5的环境中,我同意。最好是polyfill Object.create,然后使用
      newy()
      developer.mozilla.org提供的polyfill只是
      x.prototype=y.prototype
      。这不会创建一个引用吗?@Eliasdx:
      x.prototype=y.prototype
      不符合您的要求(即,将x.ptototype设置为从y.prototype继承的空对象)。再次检查。避免在
      CustomError
      赋值中调用
      newerror
      ,因为它在
      CustomError
      上调用构造函数,而留下堆栈跟踪数据。支持使用原型扩展名(
      CustomError.prototype=Object.create(Error);
      )@Raynos为什么使用Object.create(Error)而不是new Error?你能澄清两者之间的区别吗?“对于extend的合理实施”什么?我不明白。Javascript扩展对象模式是许多Javascript框架实现的一种常见设计模式,例如jQuery@Mikko:是的,我知道,但我不明白这句话。NiklasBaumstark,这是一个免责声明,说我希望在环境中存在一些合理的extend实现。LOL@extend也是一种设计模式。这是一个实用函数-我想说扩展是一种模式,因为它通常以许多原型方式被利用,而不限于一个库/函数。有些框架也调用extend()函数。并非所有库都尊重
      name
      变量。例如,需要自定义错误
      prototype
      error.prototype
      下降。事实上,根据对象的状态,如果您不100%小心,您可能会遇到麻烦,因为依赖原型链时名称可能会发生变异,因此不那么脆弱,更符合OOP习惯。