John Resig的OO JavaScript实现生产安全吗?

时间:2010-09-28 22:14:27

标签: javascript jquery oop

很长一段时间以来,我一直在努力使我的JavaScript更加面向对象。我已经看了几个不同的实现,但我无法决定是否有必要。

我想回答的是以下问题

  • John Resig's简单的继承结构是否可以安全地用于生产?
  • 有没有办法说出它的测试情况?
  • 除了Joose我还有其他选择吗?我需要一个易于使用,快速且稳健的产品。它还需要与jQuery兼容。

3 个答案:

答案 0 :(得分:19)

咦。对我而言,它看起来要复杂得多。

实际上更仔细地看一下,我真的对于在方法中提供this._super()它正在做什么做出异常,以调用超类方法。

代码引入了对typeof==='function'的依赖(某些对象不可靠),Function#toString(argh,函数分解也不可靠),并根据您是否使用了序列决定是否换行函数体中的字节_super(即使您只在字符串中使用它。如果您尝试例如。this['_'+'super']它将失败)。

如果你在函数对象上存储属性(例如MyClass.myFunction.SOME_PRIVATE_CONSTANT,你可以这样做以保持命名空间清洁),包装将阻止你获得这些属性。如果在方法中抛出异常并捕获同一对象的另一个方法,_super将最终指向错误的东西。

这一切只是为了让你的超类同名方法更容易调用。但我不认为在JS中特别难以做到这一点。它对自己的好处太聪明了,并且在整个过程中使整体变得不那么可靠。 (哦,并且arguments.callee在严格模式下无效,尽管这并不是他的错,因为在发布之后就发生了。)

这就是我目前用于课程的内容。我并不认为这是“最好的”JS类系统,因为有加载不同的方法和一些你可能想要添加或不添加的不同功能。但它非常轻巧,旨在成为“JavaScript”,如果这是一个词。 (事实并非如此。)

Function.prototype.makeSubclass= function() {
    function Class() {
        if (!(this instanceof Class))
            throw 'Constructor function requires new operator';
        if ('_init' in this)
            this._init.apply(this, arguments);
    }
    if (this!==Object) {
        Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
        Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
    }
    return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};

它提供:

  1. 防止意外丢失new。另一种方法是默默地将X()重定向到new X(),以便错过new。这是一个最好的折腾;我去了显式错误,以便一个人不习惯在没有new的情况下写作,并导致其他未定义的对象出现问题。无论哪种方式都比不可接受的JS默认值this.属性落在window上并且以后神秘地出错。

  2. 一个可继承的_init方法,因此您不必编写构造函数 - 除了调用超类构造函数之外什么都不做。

  3. 这就是全部。

    以下是如何使用它来实现Resig的示例:

    var Person= Object.makeSubclass();
    Person.prototype._init= function(isDancing) {
        this.dancing= isDancing;
    };
    Person.prototype.dance= function() {
        return this.dancing;
    };
    
    var Ninja = Person.makeSubclass();
    Ninja.prototype._init= function() {
        Person.prototype._init.call(this, false);
    };
    Ninja.prototype.swingSword= function() {
        return true;
    };
    
    var p= new Person(true);
    p.dance(); // => true
    
    var n = new Ninja();
    n.dance(); // => false
    n.swingSword(); // => true
    
    // Should all be true
    p instanceof Person &&
    n instanceof Ninja && n instanceof Person
    

    超类调用是通过专门命名所需的方法并call来完成的,有点像Python。如果您想避免再次命名_super,那么可以Person成员添加到构造函数中(因此您要说Ninja._super.prototype._init.call,或者{{1} }})。

答案 1 :(得分:5)

JavaScript是基于原型的,而不是基于类的。我的建议不是打击它并以JS的方式声明子类型:

MyDerivedObj.prototype = new MySuperObj();
MyDerivedObj.prototype.constructor = MyDerivedObj;

答案 2 :(得分:5)

了解如何在不使用继承的情况下获得多少。将其视为一种性能破解(在不需要真正必要的情况下不情愿地应用),而不是设计原则。

在像JS这样的高度动态语言中,很少需要知道对象是否是 Person。您只需知道是否具有 firstName属性或eatFood方法。您通常不需要知道对象是否是数组;如果它有一个length属性和一些以整数命名的其他属性,那通常就足够了(例如Arguments对象)。 “如果它像鸭子一样走路,像鸭子一样嘎嘎叫,那就是鸭子。”

// give back a duck
return { 
  walk: function() { ... }, 
  quack: function() { ... } 
};

是的,如果您正在制作大量小对象,每个小对象都有几十种方法,那么无论如何都要将这些方法分配给原型,以避免在每个实例中创建数十个插槽的开销。但将其视为减少内存开销的一种方法 - 仅仅是优化。并且通过隐藏在某种工厂函数后使用new来帮助您的用户,因此他们甚至不需要知道如何创建对象。他们只需要知道它有方法foo或属性bar

(请注意,在这种情况下,您不会真正建模经典继承。它仅仅相当于定义单个类以获得共享vtable的效率。)