代码分享:体现js灵活性的def.js

def.js是以前在研究js继承的时候发现的一个颇有趣的js,恰巧如今前端团队中每周进行一次分享,就翻出来整理成一篇小文章javascript

先看一段def.js实现继承的方式前端

def ("Person") ({
    init: function(name){
        this.name = name;
    },
	
    speak: function(text){
        alert(text || "Hi, my name is " + this.name);
    }
});

def ("Ninja") < Person ({
    init: function(name){
        this._super();
    },
	
    kick: function(){
        this.speak("I kick u!");
    }
});

var ninjy = new Ninja("JDD");

ninjy.speak();
ninjy.kick();
复制代码

能够看到是以 < 实现的Ninja继承于Personjava

js中,当两个对象进行算术运算或大小比较时,若是运算符两边不是数值,则调用valueOf方法,因此def.js必定是重写了valueOf,在里面实现了继承git

下面看def.js的源码(为了阅读上下文方便,删除了中间空行)github

(function(global){
// def方法返回就是deferred方法,因此在继承时执行的valueOf为下文中看到的deferred.valueOf
    var deferred;
// extend方法是经过混入的方式把deferred接收到的参数做为对象属性
    function extend(source){
        var prop, target = this.prototype;
        for(var key in source) if(source.hasOwnProperty(key)){
            prop = target[key] = source[key];
            if('function' == typeof prop){
// 这两个属性是为了下文中实现._super调用超类的同名方法,起到标记做用
                prop._name = key;
                prop._class = this;
            }
        }
        return this;
    }
// 此方法用来调用超类的同名方法
    function base(){
// callee已经在es5的严格模式中被弃用
        var caller = arguments.callee.caller;
        return caller._class._super.prototype[caller._name]
            .apply(this, arguments.length ? arguments : caller.arguments);
    }
    function def(context, klassName){
        klassName || (klassName = context, context = global);
// 在此处把经过def方法建立的类挂载到了global上
        var Klass = context[klassName] = function Klass(){
            if(context != this){
                return this.init && this.init.apply(this, arguments);
            }
// 把当前对象记录到deferred中,方便<左侧继承
            deferred._super = Klass;
// 把超类后面的参数暂存在继承事后再把这些属性进行混入,相似一开始的例子中Person后面跟的参数
            deferred._props = arguments[0] || { };
        }
        Klass.extend = extend;
        deferred = function(props){
            return Klass.extend(props);
        };
        function Subclass(){ }
        deferred.valueOf = function(){
            var Superclass = deferred._super;
            if(!Superclass){
                return Klass;
            }
            Subclass.prototype = Superclass.prototype;
            var proto = Klass.prototype = new Subclass;
            Klass._class = Klass;
            Klass.toString = function(){
              return klassName;  
            };
            proto.constructor = Klass;
// 这个地方我把这两句放到一块儿的缘由,一个_super是在Klass对象上的,一个是在Klass.prototype上的
// 不明白的请复习原型链跟new的原理
            Klass._super = Superclass;
            proto._super = base;
            deferred(deferred._props);
        };
        return deferred;
    }
    global.def = def;
}(this));
复制代码

最后还有一点就是def ("Ninja") < Person()这句话的执行顺序app

  1. def("Ninja")返回一个deferred
  2. Person()设置deferred._super跟deferred._proto
  3. 左侧执行valueOf即deferred.valueOf实现继承

固然现在es8都要来了,def.js也没什么使用场景了ui

相关文章
相关标签/搜索