Js 控件编写 继承:extend、mixin和plugin(一)
Js?繼承:extend、mixin和plugin(一)
?
簡介:
我們編寫前端控件時,需要給控件建立一個體系,面向?qū)ο笫且粋€很合適的方式,但是JS本身對面向?qū)ο蟮囊恍└拍钪С制?#xff0c;特別是繼承的特性方面,那么我們就必須通過一系列的方式來實現(xiàn)繼承。
?
Extend方式:
Extend方式非常貼近面向?qū)ο笳Z言中的類繼承,這種方式使用原型鏈的方式來實現(xiàn)繼承。原型鏈的繼承方式有幾個缺點:
1)缺少針對父類的引用,例如:
?
function?A(){
//初始化A操作
}
A.prototype?=?{
method1:function(){
//A的一系列操作
}
}
function?B(){
//初始化B的操作
}
B.prototype?=?new?A();
B.method1?=?function(){
//先執(zhí)行?A.method1的方法
//執(zhí)行自己的方法
}
?
那么此時如何在調(diào)用A的method1方法呢?我們沒有java中的’super’對象也缺少C#中的’base’對象,當然我們可以換一種寫法,來解決這個問題:
?
var??aobj?=?new?A();?
B.prototype?=?aobj;
B.method1?=?function(){
aobj.method1.call(this);//先執(zhí)行?A.method1的方法
//執(zhí)行自己的方法
}
?
但是我們必須能緩存剛才的?aobj對象,方便在調(diào)用B.method1時取得到,所以我們就引入’superclass’字段,放在構(gòu)造函數(shù)B上作為靜態(tài)屬性,調(diào)用時:B.superclass.method1.call(this),下面是實現(xiàn):
?
function?extend(subclass,superclass){
var?superObj?=?new?superclass();
subclass.prototype?=?superObj;
subclass.superclass?=?superObj;
return?subclass;
}
?
上面的函數(shù)解決了superclass的問題但是又引入了新的問題,下面我們一一來講。
2)破壞了對象的constructor屬性,這個屬性在使用繼承的過程中非常有用,它指向的是對象的構(gòu)造函數(shù),例如:
?
function?A(){}
//未繼承?A時
function?B(){}
var?b?=?new?B();
alert(b.constructor?===?B)?//true
?
//B繼承A?
extend(B,A);?
b1?=?new?B();?
alert(b1.constructor?===?B)?//?false?
alert(b1.constructor?===?b.constructor)?//false
?
這樣的結(jié)果絕對不是我們需要的,否則我們在編寫方法的過程中調(diào)用,B.supercalss.constructor.call(this)?或者?B.superclass.constructor.superclass?會出現(xiàn)混亂,我們怎么辦呢,繼續(xù)改進extend方法,矯正constructor?屬性:
?
function?extend(subclass,superclass){
var?superObj?=?new?superclass();
subclass.prototype?=?superObj;
????superObj.constructor?=?subclass;//矯正?constructor屬性
subclass.superclass?=?superObj;
return?subclass;
}
?
到這里看似解決了繼承鏈的問題,但是此時我們來看一下下面情形:
?
function?C?(){}?
extend(C,B);
var?c?=?new?C();?
alert(c.constructor.superclass.constructor);//C
?
上面的結(jié)果意外的不是B?而是?C,這是什么原因呢,我們看剛才矯正constructor?屬性以及上面一句:
?
subclass.prototype?=?superObj;
superObj.constructor?=?subclass;
?
我們將C的prototype的constructor修改為了C?,由于subclass.superclass?=?superObj;那么C的superclass跟C?的prototype是同一個對象,那么?c.constructor.superclass.constructor等同于C.prototype.constructor?結(jié)果就是?C,那么我們需要做一下修改:
?
function?extend(subclass,superclass){
var?superObj?=?new?superclass();
subclass.prototype?=?superObj;
????superObj.constructor?=?subclass;//矯正?constructor屬性
subclass.superclass?=?new?superclass();
return?subclass;
}
?
此時我們再來調(diào)用一下:
?
alert(c.constructor.superclass.constructor);//B
?
此時的還有什么問題呢?我們來做一下實驗:
?
function?A?(config){
??console.log('a?constructor,config:'?+?config);
}
A.prototype?=?{
??method?:?function(){
????console.log('a?runing');
??}
};
function?B?(config){
??this.constructor.superclass.constructor.call(this,config);
??console.log('b?constructor,config:'?+?config);
}
extend(B,A);
function?C?(config){
??this.constructor.superclass.constructor.call(this,config);
??console.log('c?constructor,config:'?+?config);
}
extend(C,B);
var?c?=?new?C('hello');
c.method();
?
輸出結(jié)果:
?
a?constructor,config:undefined?
a?constructor,config:undefined?
b?constructor,config:undefined?
b?constructor,config:undefined?
b?constructor,config:undefined?
Uncaught?RangeError:?Maximum?call?stack?size?exceeded
?
我們看到?jīng)]有輸出我們希望的結(jié)果,這里有2個問題,
1.?產(chǎn)生了循環(huán)調(diào)用
2.?未實例化對象前,實例化了多個父類對象,而且這些實例初始化時傳入的參數(shù)為空,極易出現(xiàn)錯誤。
解決死循環(huán)我們只需要把this.constructor.superclass?替換為?對應(yīng)的?B.superclass即可:
?
function?B?(config){
??B.superclass.constructor.call(this,config);
??console.log('b?constructor,config:'?+?config);
}
function?C?(config){
??C.superclass.constructor.call(this,config);
??console.log('c?constructor,config:'?+?config);
}
?
針對調(diào)用extend時生成多個實例我們引入方法:
?
function?create(proto,?c)?{
????function?F()?{
????}
????F.prototype?=?proto;
????var?o?=?new?F();
????o.constructor?=?c;
????return?o;
}
?
在extend方法中我們這樣調(diào)用:
?
var?superObj?=?create(superclass.prototype,subclass);
subclass.prototype?=?superObj;
subclass.superclass?=?create(superclass.prototype,superclass);??
?
此時我們的prototype?屬性和superclass屬性都不需要實例化對象,完整的extend方法如下:
?
function?extend(subclass,superclass){
????function?create(proto,?c)?{
????????function?F()?{
????????}
????????F.prototype?=?proto;
????????var?o?=?new?F();
????????o.constructor?=?c;
????????return?o;
????}
var?superObj?=?create(superclass.prototype,subclass);
????subclass.prototype?=?superObj;
????subclass.superclass?=?create(superclass.prototype,superclass);?
return?subclass;
}
?
這樣在執(zhí)行上面的代碼即得到:
?
a?constructor,config:hello
b?constructor,config:hello
c?constructor,config:hello
a?runing?
?
今天先寫到這里,接下來我會把控件的繼承機制一下,如果有時間,把一些編寫js控件的經(jīng)驗分享出來,希望對大家有幫助。
轉(zhuǎn)載于:https://www.cnblogs.com/zaohe/archive/2012/10/13/2723148.html
總結(jié)
以上是生活随笔為你收集整理的Js 控件编写 继承:extend、mixin和plugin(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人人网SDK Demo项目学习获取系统L
- 下一篇: 【原】动态申请二维数组并释放的三种方法