JavaScript“类”继承的横向比较
博客专区 > netxdiy 的博客 > 博客详情
JavaScript“类”继承的横向比较
netxdiy 发表于3年前
JavaScript“类”继承的横向比较
  • 发表于 3年前
  • 阅读 15
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

本文最早发表于2008-06-07

首入眼帘,代码:

/**
     * Utility to set up the prototype, constructor and superclass properties to
     * support an inheritance strategy that can chain constructors and methods.
     * Static members will not be inherited.
     *
     * @method extend
     * @static
     * @param {Function} subc   the object to modify
     * @param {Function} superc the object to inherit
     * @param {Object} overrides  additional properties/methods to add to the
     *                              subclass prototype.  These will override the
     *                              matching items obtained from the superclass 
     *                              if present.
     */
    extend: function(subc, superc, overrides) {
        if (!superc||!subc) {
            throw new Error("extend failed, please check that " +
                            "all dependencies are included.");
        }
        var F = function() {};
        F.prototype=superc.prototype;
        subc.prototype=new F();
        subc.prototype.constructor=subc;
        subc.superclass=superc.prototype;
        if (superc.prototype.constructor == Object.prototype.constructor) {
            superc.prototype.constructor=superc;
        }
    
        if (overrides) {
            for (var i in overrides) {
                if (L.hasOwnProperty(overrides, i)) {
                    subc.prototype[i]=overrides[i];
                }
            }
            L._IEEnumFix(subc.prototype, overrides);
        }
    }

然后是 YUI 的儿子,Ext JS:

/**
         * 继承,并由传递的值决定是否覆盖原对象的属性
         * 返回的对象中也增加了override()函数,用于覆盖实例的成员
         * @param {Object} subclass 子类,用于继承(该类继承了父类所有属性,并最终返回该对象)
         * @param {Object} superclass 父类,被继承
         * @param {Object} overrides (该参数可选) 一个对象,将它本身携带的属性对子类进行覆盖
         * @method extend
         */
        extend : function(){
            // inline overrides
            var io = function(o){
                for(var m in o){
                    this[m] = o[m];
                }
            };
            return function(sb, sp, overrides){
                if(typeof sp == 'object'){
                    overrides = sp;
                    sp = sb;
                    sb = function(){sp.apply(this, arguments);};
                }
                var F = function(){}, sbp, spp = sp.prototype;
                F.prototype = spp;
                sbp = sb.prototype = new F();
                sbp.constructor=sb;
                sb.superclass=spp;
                if(spp.constructor == Object.prototype.constructor){
                    spp.constructor=sp;
                }
                sb.override = function(o){
                    Ext.override(sb, o);
                };
                sbp.override = io;
                Ext.override(sb, overrides);
                return sb;
            };
        }()

注:上一个是 v2.0 的;Ext JS v2.1 改进了一点,见:

/**
         * Extends one class with another class and optionally overrides members with the passed literal. This class
         * also adds the function "override()" to the class that can be used to override
         * members on an instance.
         * * <p>
         * This function also supports a 2-argument call in which the subclass's constructor is
         * not passed as an argument. In this form, the parameters are as follows:</p><p>
         * <div class="mdetail-params"><ul>
         * <li><code>superclass</code>
         * <div class="sub-desc">The class being extended</div></li>
         * <li><code>overrides</code>
         * <div class="sub-desc">A literal with members which are copied into the subclass's
         * prototype, and are therefore shared among all instances of the new class.<p>
         * This may contain a special member named <tt><b>constructor</b></tt>. This is used
         * to define the constructor of the new class, and is returned. If this property is
         * <i>not</i> specified, a constructor is generated and returned which just calls the
         * superclass's constructor passing on its parameters.</p></div></li>
         * </ul></div></p><p>
         * For example, to create a subclass of the Ext GridPanel:
         * <pre><code>
    MyGridPanel = Ext.extend(Ext.grid.GridPanel, {
        constructor: function(config) {
            // Your preprocessing here
        	MyGridPanel.superclass.constructor.apply(this, arguments);
            // Your postprocessing here
        },
        yourMethod: function() {
            // etc.
        }
    });
</code></pre>
         * </p>
         * @param {Function} subclass The class inheriting the functionality
         * @param {Function} superclass The class being extended
         * @param {Object} overrides (optional) A literal with members which are copied into the subclass's
         * prototype, and are therefore shared between all instances of the new class.
         * @return {Function} The subclass constructor.
         * @method extend
         */
        extend : function(){
            // inline overrides
            var io = function(o){
                for(var m in o){
                    this[m] = o[m];
                }
            };
            var oc = Object.prototype.constructor;
            
            return function(sb, sp, overrides){
                if(typeof sp == 'object'){
                    overrides = sp;
                    sp = sb;
                    sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
                }
                var F = function(){}, sbp, spp = sp.prototype;
                F.prototype = spp;
                sbp = sb.prototype = new F();
                sbp.constructor=sb;
                sb.superclass=spp;
                if(spp.constructor == oc){
                    spp.constructor=sp;
                }
                sb.override = function(o){
                    Ext.override(sb, o);
                };
                sbp.override = io;
                Ext.override(sb, overrides);
                sb.extend = function(o){Ext.extend(sb, o);};
                return sb;
            };
        }(),

其实啊,Ext JS 好、YUI 也好,它们那一套的继承都源自这个前辈 Kevin Lindsey
要搞清楚这套继承来龙去脉,这 Article 就千万不能错过了:
http://kevlindev.com/tutorials/javascript/inheritance/index.htm
文章问世时间是:Saturday, April 13th, 2002 。

最后,看到一位仁兄的推荐,来自 John Resig 的方案好像“集百家之所长”,见:

// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? //b_super/b/ : /.*/;
  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);       
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.constructor = Class;
    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();

还有其他基于类的继承方案,如 Lazy Inheritance、Dean Edwards 的 Base2,不是说不好,而是很好,好到太复杂了(Lazy Inheritance 的简介像论文似的—题外话),——个人认为过于复杂有点违背 JS 短小精悍的意思,什么东西过了谱就不行的啦 嘿嘿 所以第一眼就枪毙了。

总结一下..嗯 还没太多的心得,还是台湾的一位朋友说得好:

無奈
  感覺上又回到原始時代,或者說,回到比原始時代更久遠的上古時代,連建構基本的物件架構就有許多的不便,這樣複雜的結構實在有礙思考。想必在Scripting 領域的 OO 或甚至 Design Patten 又會發展成另一個 Knowledge Domain 吧!過去在其他物件導向語言使用的 Patten,硬是要套到這上面來不見得是一件明智的作法,畢竟 Script 的特性就是如此,與其他語言有一定程度的差別,但也正因為如此,不是 Scripting 是有缺陷的語言,而是在這個領域的設計及規劃方法,全世界都欠缺足夠的經驗,因此就不像使用 Java 或 C# 那般,可以歡歡喜喜的導入前人歸納的各種設計模式。

注:本文的重点是类继承,如果采用 JS 原生的“原型”继承 则简单很多——请君勿鄙之,因为存在就是合理。Just take a look 原型继承 by Douglas Crockford,比标准方案Prototype = new XX(); Make Sense很多,仅是五六行代码。

共有 人打赏支持
粉丝 3
博文 2
码字总数 163257
×
netxdiy
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: