如何使用原型来实现Exception类

How to use prototyping to implement an Exception class

本文关键字:Exception 实现 何使用 原型      更新时间:2023-09-26

我试图在JavaScript中创建一个Exception类,我有一个小问题,虽然我一直在使用JavaScript很长一段时间,我从来没有真正使用原型正确

这是我的代码,
// load the Object Prototype
Exception = Object;
Exception.prototype = new function () {
    // set defaults
    this.name = "Exception";
    this.message = "";
    this.level = "Unrecoverable";
    this.html = "No HTML provided";
    // code so that the console can get the name from this.name insted of using [object Object]
    this.getName = function(){
        return this.name;
    }
    // this is the exec of the object prototype the code that is executed when the new Exception call is made
    this.exec = function(msg, name, lvl, html){
        // create a return variable
        var ret;
        // check that msg is defined and is not empty
        if(typeof(msg) == "undefined" || msg == ""){
            throw new Exception("Can't throw exception without a msg");
        }
        // set up this Exception Object values
        this.name = (typeof(name) == "undefined")? this.name : name;
        this.level = (typeof(lvl) == "undefined")? this.level : lvl;
        this.message = msg;
        this.html = (typeof(this.html) == "undefined")? this.html : html;
        // delete the getName function so it does not get set though to the console
        delete this.getName;
        // save the Exception object to our return variable
        ret = this;
        // re add the getName object to the Exception Object so that it can be called from the console
        this.getName = function(){
            return this.name;
        }
        // return the saved Exception object without the getName method
        return ret;
    }
}

但是由于某些原因在控制台中它返回字符串作为msg

的参数

这是我收到的控制台输出

throw new Exception("test");
test
    0: "t"
    1: "e"
    2: "s"
    3: "t"
    length: 4
    __proto__: String

任何帮助都将非常感谢

从你的代码来看,我认为这是你想要做的:

Exception.prototype = new Error;
Exception.prototype.constructor = Exception;
function Exception(message, name, level, html) {
    if (typeof message !== "string")
        throw new Exception("Expected an error message.");
    this.message = message;
    this.name = name || "Exception";
    this.level = level || "Unrecoverable";
    this.html = html || "No HTML provided";
}

查看MDN文档获取更多信息。

编辑:如果你有原型继承的问题,那么我建议你花一些时间了解它:https://stackoverflow.com/a/8096017/783743

这是一个例外'类'的例子,满足您的要求:

/*
  This is a constructor function. It creates a new Exception object.
  Use it with the 'new' keyword , e.g. var e = new Exception("Another error").
 */
function Exception( message, name, level, html ) {   
    if ( !message ) {
        throw 'No exceptions without a message!';
    }  
    /*
      These properties may have different values for each instance so set
      them here in the constructor rather than adding them to the prototype.
     */
    this.message = message;
    this.name = name || "Exception";
    this.level = level || "Unrecoverable"; 
    this.html = html || "No HTML provided"; 
 }
/*     
  Overwrite the toString method inherited from Object.prototype
  by adding a toString method that shows the name and message.
  This method is the same for each instance so add it to the
  prototype object instead of having to create and add it to
  'this' in the constructor every time an instance is created.
 */
Exception.prototype.toString = function () {
    return this.name + ': ' + this.message; 
}

Try it out

try {
    throw new Exception("test");
} catch (e) {
    console.log( e instanceof Exception);    // true
    console.log( e instanceof Error);        // false
    console.log( e );       
    // Exception {message: "test", name: "Exception", level: "Unrecoverable"...
}
throw new Exception("test");                 // Uncaught Exception: test   


不像上面那样在Exception.prototype中添加toString方法,另一种确保Exception对象的toString方法返回namemessage的方法是继承内置Error对象的原型。

Exception.prototype = Error.prototype;

这也使得Exception对象的默认name如果没有在Exception构造函数中设置,则为'Error' -但在我们的情况下不是必需的。

这也意味着任何添加到Error.prototype的属性都将存在。

var e = new Exception("Another");   
Error.prototype.about = 'This is an Error';
console.log( e.about );                  // 'This is an Error'
console.log( e instanceof Exception);    // true
console.log( e instanceof Error);        // true

或者,我们可以从Error实例继承,而不是从Error.prototype继承,正如Aadit M Shah的回答。

Exception.prototype = new Error();

以创建一个新的Error对象为代价,这避免了Exception.prototype的变化影响Error.prototype的潜在问题,因为它们现在不是指向同一个对象。Error.prototype的变化仍然会影响Exception.prototype,因为它们是通过Error对象继承的。

似乎满足您需求的最简单的方法可能是完全避免从Error对象或Error.prototype继承,而只是将自己的toString方法添加到Exception.prototype中,如第一个示例所示。

不得不编辑这个,因为我之前发布的一些信息是不真实的或非常有用的。

我之前说过,JavaScript没有私有方法或属性;这是不真实的。私有方法可以通过使用闭包来实现:https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures根据文档,它会带来性能损失。

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
})();

要"子类化"一个现有的对象,你必须使用原型,因为JavaScript不是基于类的语言。下面是一个展示JavaScript中原型的缺点的例子。下面这个优秀的文档没有提到或者至少没有给出适当的警告的是,"子"对象共享"父"对象的一个惰性复制实例。更准确地说,如果两个对象具有相同的原型(共享相同的父对象),则它们共享父对象属性的相同INSTANCE。https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model下面是一些示例代码:

function Employee () {
  this.name = "";
  this.dept = "general";
  this.objectVal=[];
}
function Manager () {
  this.reports = [];
}
Manager.prototype = new Employee;
var bob=new Manager();
bob.name="bob";
bob.objectVal.push("should not be in jane");
var jane=new Manager();
jane.name="jane";
console.log(jane.name);//correct
console.log(jane.objectVal);//incorrect shows ["should not be in jane"]

简单值将正确,但对象值将不正确。在该文档后面的部分给出了这个问题的解决方案,即:

function Manager () {
  Employee.call(this);
  this.reports = [];
}
Manager.prototype = new Employee;

Manager中的Employee.call(this)所做的是在Manager的this上下文中调用Employee函数。所以这两行this.name, this.dept成为Manager的直接属性,不是通过原型,而是通过它们在Manager的this上下文中初始化的事实。

直线经理。prototype = new Employee;可以省略,但是(bob instanceof Employee)将计算为false。

所以当创建你自己的类时,你可以把所有需要"由子实例唯一继承"的属性和对象值放在"父"中。语法的东西。

父类的方法可以(根据一些文档应该)用原型语法指定:

//var Employee=function(){....}
Employee.prototype.EmployeeMethod=function(){}
//or
//var Employee=function(){....}
Employee.prototype={EmployeeMethod:function(){},AnotherOne:function(){},....};

如果你想"子类化"错误(有错误作为异常原型),那么问题是你没有写错误,我不能使用错误作为原型,并使用它的属性:

var Exception=function(msg){
// both don't work
//    Error.call(Exception.prototype,msg);
    Error.call(this,msg);
}
Exception.prototype=new Error;
var e=new Exception("my message");
console.log(e.message);//empty string

不确定为什么会这样,调用Error.call(this,msg)会将Error的属性设置为Exceptions属性(将它们复制到Exception),如果它们位于定义为this. someproperty的Error函数体中。调用Error.call(Exception.prototype,msg)不会将这些属性复制到Exception,但Exception仍然会通过原型链拥有这些属性。

下面的链接是一篇文章,你可以找到一个优雅的解决方案,子类化,虽然我不完全理解的代码(解决方案是在第2部分):http://www.lshift.net/blog/2006/07/24/subclassing-in-javascript-part-1

首先解决OP的"子类化"错误的原因;有几个第三方的JavaScript控制台在那里为IE。

我试过Firebug lite,它可以满足你的需要。在你的控制台中没有更多的[object: object]当记录一些东西时:

https://getfirebug.com/firebuglite