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
固然現在es8都要來了,def.js也沒什麼使用場景了ui