Javascript 如何使用原型实现异常类

Javascript 如何使用原型实现异常类,javascript,prototype,Javascript,Prototype,我试图在JavaScript中创建一个异常类,但我在原型设计方面遇到了一个小问题,尽管我已经使用JavaScript很长时间了,但我从未真正正确地使用原型设计 这是我的密码 // load the Object Prototype Exception = Object; Exception.prototype = new function () { // set defaults this.name = "Exception"; this.message = "";

我试图在JavaScript中创建一个异常类,但我在原型设计方面遇到了一个小问题,尽管我已经使用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

任何帮助都将不胜感激

我必须编辑此内容,因为我以前发布的一些信息不是真实的,也不是很有帮助

我之前说过JavaScript没有私有方法或属性;这是不真实的。私有方法可以通过使用闭包来实现: 根据文档,它会带来性能损失

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
})();
要“子类化”现有对象,您必须使用prototype,因为JavaScript不是基于类的语言。下面是一个暴露JavaScript中原型缺点的示例。 以下优秀文档没有提到或至少没有给出适当的警告的是,“子”对象共享一个“父”对象的延迟复制实例。更准确地说,如果两个对象具有相同的原型(共享相同的父对象),则它们共享该父对象属性的相同实例。 其中的一些示例代码:

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的这个上下文调用Employee函数。因此,this.name、this.dept行成为Manager的直接属性,不是通过原型设计,而是通过它们在Manager的this上下文中初始化的事实

直线经理.prototype=新员工;可以省略,但(员工的bob instanceof)将计算为false

所以,在创建自己的类时,可以使用this.something语法将所有需要“由子实例唯一继承”的属性以及对象值放在“parent”中

“parent”的方法可以(根据一些文档应该)用prototype语法指定:

//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.call(Exception.prototype,msg)不会将属性复制到Exception,但Exception仍然会通过原型链拥有这些属性

下面的链接是一篇文章,您可以在其中找到一个优雅的子类化解决方案,尽管我没有完全理解代码(解决方案在第2部分):

从您的代码判断,我认为这就是您想要做的:

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";
}
有关更多信息,请参阅


编辑:如果您在原型继承方面遇到问题,那么我建议您花一些时间来了解它:

这是一个满足您要求的异常“类”示例:

/*
  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 {
    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
方法返回其
名称
消息
的方法是从内置
错误
对象的原型继承

Exception.prototype = Error.prototype;
如果未在
异常
构造函数中设置
异常
对象,这也会使该对象的默认
名称
出现“错误”-但在本例中不需要这样做

这也意味着添加到
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
或者,我们可以从一个
错误
实例继承,而不是从
错误.prototype继承,就像Aadit M Shah的回答一样

Exception.prototype = new Error();
以创建一个新的
错误
对象为代价,这避免了
异常.prototype
更改的潜在问题,从而影响
错误.prototype
。对
Error.prototype
的更改仍将影响
Exception.prototype
,因为它们是通过
Error
对象继承的


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

解决OP“子类化”的原因首先是错误;IE有几个第三方JavaScript控制台

我试过Firebug lite,它可以满足你的需要。记录以下内容时,控制台中不再显示[object:object]:


您的代码中有很多古怪的东西。我建议从新开始,先阅读。JavaScript没有类
Exception=Object
不会加载原型,它会生成
Exception
对象的另一个名称。我不知道你认为
新函数()…
在做什么,但你正在覆盖
对象。prototype
。WTF?
Object.prototype
似乎不可写(至少在FF中),但您至少正在尝试覆盖它。@FelixKling对象和基本值之间没有区别。在
x=y
之后,
x
的值与
y
之前的值相同。@melpomene程序员没有内存地址,但JavaScript中有内存地址。但是,只有JavaScript引擎可以访问和操作它们。事实上,在每一种编程语言中创建的每个变量都有与其相关联的内存地址,因为变量