1

我正在尝试在 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

任何帮助将不胜感激

4

4 回答 4

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";
}

有关更多信息,请参阅MDN 文档

编辑:如果您在原型继承方面遇到问题,那么我建议您花一些时间了解它:https ://stackoverflow.com/a/8096017/783743

于 2013-01-12T16:21:59.537 回答
1

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

/*
  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   


除了向上面添加toString方法Exception.prototype之外,另一种确保对象的toString方法Exception返回它们name的方法message是从内置Error对象的原型继承。

Exception.prototype = Error.prototype;

如果未在构造函数中设置对象,这也会使对象的默认name值为“错误” - 但在我们的情况下不需要这样做。ExceptionException

这也意味着添加到的任何属性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.prototype我们可以从ErrorAadit M Shah 的回答中的实例继承,而不是继承。

Exception.prototype = new Error();

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

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

于 2013-01-12T17:12:48.840 回答
0

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

我试过 Firebug lite,它会做你需要的。记录某些内容时,控制台中不再有 [object:Object] :

https://getfirebug.com/firebuglite

于 2013-01-14T06:52:35.187 回答
0

不得不编辑这个,因为我之前发布的一些信息不是真的或很有帮助。

我之前说过,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 中原型的缺点的示例。以下优秀文档没有提及或至少给出适当警告的是“子”对象共享“父”对象的延迟复制实例。更准确地说,如果两个对象具有相同的原型(共享相同的父对象),它们共享该父对象属性的相同实例。 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 上下文中初始化的事实。

行 Manager.prototype = new Employee; 可以省略,但 (bob instanceof Employee) 将评估为 false。

因此,在创建自己的类时,您可以使用 this.something 语法将所有需要“由子实例唯一继承”并且是“父”中的对象值的属性。

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

//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

于 2013-01-12T16:18:18.427 回答