javascript物件導向包裝類別Class封裝類別庫剖析_javascript技巧
javascript是入門門檻很低的語言,甚至一個從來沒有接觸過javascript的技術人員,幾小時內就可以寫出一個簡單有用的程式碼。
但如果因此你就下結論:javascript是門簡單的語言。那你就大錯特錯了。想寫出高效能的程式碼,同樣需要具備一個高階程式設計師的基本素養。
一個java或c 程式設計師,不一定能寫出高效能的javascript程式碼,但更容易寫出高效能的javascript程式碼。
javascript的簡單是基於它「胸襟廣闊」的包容性。它聲明時,不需要指定類型,甚至可以任意的轉換類型。它面向對象,卻沒有類別(Class)的限制。它是一門崇尚自由又非常嚴謹的語言,如果你是自由主義者,那麼,擁抱javascript吧!
物件導向程式設計(OOP)是一種流行的程式設計方法。但javascript的OOP,較之JAVA、c 有很大的同,主要反映它的繼承方式不同。 javascript是基於原型PROTOTYPE繼承的。所有物件都是基於原型鏈,最終追述到Object物件。
這裡不想討論過多的關於javascript的繼承方式和其它語言的繼承方式的不同之處。主要討論如何封裝javascript的Class,以便更好的管理和維護基礎程式碼,減少重複程式碼,以及更好的模組化程式設計。
以下是幾個github上找到的比較好的Class封裝類別庫:
一、MY-CLASS
專案位址:https://github.com/ jiem/my-class
先看基本用法:
a、新建一個類別
(function(){
//新類別
varPerson=my.Class({
//新增靜態方法
STATIC:{
AGE_OF_MAJORITY: 18
},
//建構子
constructor:function(name,age){
this.name=name;
this.age=age;
},
//實例方法
sayHello:function(){
console.log('Hellofrom' this.name '!');
},
//實例方法
drinkAlcohol:function (){
this.age
console.log('Whiskeyorbeer?');
}
}
} );
//暴露給命名空間
myLib.Person=Person;
})();
varjohn=newmyLib.Person('John',16);
john.sayHello ();//log"HellofromJohn!"
john.drinkAlcohol();//log"Tooyoung!Drinkmilkinstead!"
b、繼承一個類別
(function(){
//Dreamer繼承Person
varDreamer=my. Class(Person,{
//建構方法
constructor:function(name,age,dream){
Dreamer.Super.call(this,name,age);
this.dream=dream ;
},
//實例方法
sayHello:function(){
superSayHello.call(this);
console.log('Idreamof' this.dream '!');
},
//實例方法
wakeUp:function(){
console.log('Wakeup!');
}
});
//Super存取父類別
varsuperSayHello=Dreamer.Super.prototype.sayHello;
//暴露給全域命名空間
myLib.Dreamer=Dreamer;
})();
varsylvester=newmyL. Dreamer('Sylvester',30,'eatingTweety');
sylvester.sayHello();//log"HellofromSylvester!IdreamofeatingTweety!"
sylvester.wakeUp();//log"Wakeup!"
程式碼如下:
程式碼如下:
程式碼如下:
程式碼如下:
//為myLib.Dreamer新增方法
my.extendClass(myLib.Dreamer,{
STATIC:{
s_dongSomeThing:function(){
//宣告一個新類別
myLib.ImaginaryTraveler=my.Class({
travel:function(){console.log('Travelingonacarpet!');},
crossOceans: function(){console.log('SayinghitoMobyDick!');}
});
(function(){
//Dreamer繼承Person實作ImaginaryTraveler的方法
varDreamer=my.Class( Person,ImaginaryTraveler,{
//建構方法
constructor:function(name,age,dream){
Dreamer.Super.call(this,name,age);
this.dream=dream ;
}
//...
});
//暴露給全域命名空間
myLib.Dreamer=Dreamer;
})();
varaladdin =newDreamer('Aladdin');
aladdininstanceofPerson;//true
aladdininstanceofImaginaryTraveler;//false
aladdin.travel();
aladdin.wakeUp(>aladdin.travel();
aladdin.wakeUp(); ;
如果怕忘記new運算子
//youcannowcalltheconstructorwithorwithoutnew
constructor:function(name,city){
if(!(thisinstanceofPerson))
this.city=citye;
}
});
下面看一下my.class的原始碼解析:
my.Class實現思路基本上是這樣的,如果只有一個參數,那麼聲明的是一個基礎類,這個參數是用來宣告新類的方法和屬以及建構子。它不是繼承而來,但它可以被繼承。
繼承的思路,就是如果有兩個參數,第一個參數做為父類別被繼承,第二參數用來宣告新類別的方法和屬性以及建構函數,它同樣可以被繼承。
如果有三個以上參數那麼,除出第一個參數做為繼承的父類,最後一個參數用宣告新類別的方法和屬性以及建構子。中間的參數是用類別來擴充新類別的方法。當然也可以透過my.extendClass擴充新方法。
同時,類別庫為commonJS和瀏覽環境都提供了支援!
/*globalsdefine:true,window:true,module:true*/
(function(){
//Namespaceobject
varmy={};
//保證AMD分模組可用
if(typeofdefine!=='undefined')
define([],function(){
returnmy;
});
elseif(typeofwindow!=='undefined ')
//保證客戶端可用
window.my=my;
else
//保證後台可用
module.exports=my;
//==== ================================================== ======================
//@methodmy.Class
//@paramsbody:Object
//@paramsSuperClass:function, ImplementClasses:function...,body:Object
//@returnfunction
my.Class=function(){
varlen=arguments.length;
varbody=arguments[len-1];/ /最後一個參數是指定本身的方法
varSuperClass=len>1?arguments[0]:null;//第一個參數是指繼承的方法,實例和靜態部分均繼承
varhasImplementClasses=len> 2;//如果有第三個參數,那麼第二個就是implementClass,這裡其實只繼承實例物件
varClass,SuperClassEmpty;
//保證建構方法
if(body.constructor=== Object){
Class=function(){};
}else{
Class=body.constructor;
//保證後面不覆蓋constructor
deletebody.constructor;
}
//處理superClass部分
if(SuperClass){
//中間件實作實例屬性的繼承
SuperClassEmpty=function(){};
SuperClassEmpty.prototype=SuperClass.prototype;
Class.prototype=newSuperClassEmpty();//原型繼承,解除引用
Class.prototype.constructor=Class;//保證constructor
Class.Super=SuperClass;//父物件存取介面
//靜態方法繼承,重載superClass方法
extend(Class,SuperClass,false);
}
//處理ImplementClass部分,其實只繼承實例屬性部分,除SuperClass#arguments[0] #和body#arguments[length-1]#
if(hasImplementClasses)
for(vari=1;i
extend(Class.prototype,arguments[i].prototype,false);
//處理本身聲明body部分,靜態要STATIC指定,實例部分要刪除STATIC部分
extendClass( Class,body);
returnClass;
};
//================================ ==============================================
/ /@methodmy.extendClass
//@paramsClass:function,extension:Object,?override:boolean=true
varextendClass=my.extendClass=function(Class,extension,override){
//靜態部分繼承靜態部分
if(extension.STATIC){
extend(Class,extension.STATIC,override);
//保證實例部分不繼承靜態方法
deleteextension.STATIC;
}}
//實例屬性繼繼承實例部
extend(Class.prototype,extension,override);
};
//=============== ================================================== ===========
varextend=function(obj,extension,override){
varprop;
//其實這裡的flase是表明,覆蓋父物件的方法
if(override===false){
for(propinextension)
if(!(propinobj))
obj[prop]=extension[prop];
}else{
///這裡其實不覆寫父物件的方法,包含toString
for(propinextension)
obj[prop]=extension[prop];
if(extension.toString!==Object.prototype.toString)
obj.toString=extension.toString;
}
};
})();
二、KLASS
項目位址:項目位址: https://github.com/ded/klass
先看使用方法:
a、新建一個類別
//宣告一個類別
varPerson=klass(function(name){
this.name=name
})
.statics ({//靜態方法
head:':)',
feet:'_|_'
})
.methods({//實例方法
walk:function() {}
})
b、繼承一個類別
複製程式碼
複製程式碼
程式碼如下:> 程式碼如下:
//SuperHuman繼承Person
varSuperHuman=Person.extend(function(name){
//自動呼叫父類別的建構方法
})
.methods ({
walk:function(){
this.supr()
this.fly()
c、字面量方式宣告一個類別
複製程式碼
程式碼如下:
varFoo=klass({
foo:0,
initialize{function(){
d、實作一個類別的方法
因為有時候你可能會想要覆寫或混合一個實例方法,可以這樣:
//可以傳遞一個字面量去繼承
varAlien=SuperHuman.extend({
beam:function(){
this .supr()
//beamintospace
}
})
varSpazoid=newAlien('Zoopo')
if(beamIsDown){
//覆蓋上beam>方法
if(beamIsDown){
//覆蓋beam Spazoid.implement({
beam:function(){
this.supr()
//fallbacktojets
this.jets()
}
})
this.jets()
}) this.jets() }
})
this.jets()
}
})
this.jets()
}
})
this.jets()
}
})
this.jets()
/**
*Klass.js-copyright@dedfat *version1.0
*https://github.com/ded/klass
*追蹤我們的軟體http://twitter.com /dedfat:)
*MIT 授權
*/
!function(context,f){
//fnTest用來驗證是否可能透過正規找出呼叫super父類別方法的方法
varfnTest=/xyz/.test(function(){xyz;})?/bsuprb/:/.*/,
noop=function(){},
proto='prototype',
isFn =function(o){
returntypeofo===f;
};
//基礎類別
functionklass(o){
returnextend.call(typeofo==f?o:noop ,o,1);
}
//包裝成借用super同名方法的函數
functionwrap(k,fn,supr){
returnfunction(){
//緩存原this.super
vartmp=this.supr;
//暫把this.super改造成借用super的同名方法above
//供o裡顯式的聲明(fnTest.text(fn)= =true)要藉用super的同名方法使用
this.supr=supr[proto][k];
//借用執行並儲存回傳值
varret=fn.apply(this,arguments);
//恢復原this.super
this.supr=tmp;
//回傳回值,保證wrap後的回傳值跟原來一致
returnret;
};
}
//如果o和super有同名方法,且o明確宣告借用super的同名方法,就wrap成一個待執行函式供使用
//如果沒有明確的宣告借用super的同名方法,或o獨有的方法,或不是方法就直接用
functionprocess(what,o,supr){
for(varkino){
//如果是非繼承方法,按方法註釋規則執行,最後都放進what
if(o.hasOwnProperty(k)){
what[k]=typeofo[k]==f
&&typeofsupr[proto][k]==f
&&fnTest.test(o[k])
?wrap(k,o[k],supr):o[k];
}
}
}
//繼承方法的實作,fromSub是用來控制是否繼承而來,上面的klass裡面fromSub是1,表明非繼承而來,構造函數不借用super執行
functionextend(o,fromSub){
//noop做為媒介類別實作原型繼承的解除引用
noop[proto]=this[proto];
varsupr=this,
prototype=newnoop(),//建立實例物件供原型繼承使用,解除引用
isFunction=typeofo==f,
_constructor=isFunction?o:this,//如果o是一個構造方法就用,否則由this來決定構造函數
_methods=isFunction?{}:o, //如果o是一個{...}應該用methods放到fn原型裡,如果裡面有initialize就是建構子,如果o是函數就由上面_constructor決定o是建構子
fn=function() {//因為kclass借助了kclass,所以最終實際上返回的就是fn,fn其實就新類別的建構子
//1如果o是{...}就會被methods直接過濾並加入fn的原型裡,如果o裡面有initialize,那麼fn的原型裡就有initialize,那麼它就是構造方法
//2如果o是function,methods什麼也添加不到fn的原型裡,但是_constructor會接受o當建構子
//3如果o是{....},同時裡面也沒有initialize,那麼就是this當建構子,如果在klass裡由call決定,顯然建構子是noop,如果在非基礎類別裡,建構子就是父類別的建構子
//由於o不是函式不會自動呼叫父類別的建構子,只是把父類別的建構子當做目前類別的建構子----這都是由於this的指向決定的
console.log(this);
if(this.initialize){
this.initialize.apply(this,arguments);
}else{
//呼叫父類別建構方法
//如上面3,o不是函數,不會呼叫父類別的建構方法
//基礎類別無父類別,不會呼叫父類別建構方法
fromSub||isFn(o)&&supr.apply(this,arguments);
//呼叫本類構造方法
//參考上面2,3要不是noop就是o
console.log(_constructor ==noop);
_constructor.apply(this,arguments);
}
};
//建構原型方法的介面
fn.methods=function(o){
process(prototype,o,supr);
fn[proto]=prototype;
returnthis;
};
//執行實作新類別原型,保證新類別的constructor
fn .methods.call(fn,_methods).prototype.constructor=fn;
//保證新類別可以被繼承
fn.extend=arguments.callee;
//新增實例方法或靜態方法, statics:靜態方法,implement實例方法
fn[proto].implement=fn.statics=function(o,optFn){
//保證o是object對象,如果o是字串,那就是添一個方法的情況,如果o是一個object物件說明是批量添加的
//因為要從o裡面拷貝
o=typeofo=='string'?(function(){
varobj= {};
obj[o]=optFn;
returnobj;
}()):o;
//新增實例方法或靜態方法,statics:靜態方法,implement實例方法
process(this,o,supr);
returnthis;
};
returnfn;
}
//後台用,nodejs
if(typeofmodule!=='undefined' &&module.exports){
module.exports=klass;
}else{
varold=context.klass;
//防衝突
klass.noConflict=function(){
context.klass=old;
returnthis;
};
//前台瀏覽器用
//window.kclass=kclass;
context.klass=klass;
}
}(this,'function');
3. 간단한 구현도 있습니다
구현 아이디어는 매우 간단합니다. 즉, ECMAScript5 프로토타입을 사용하여 Object.create 메서드를 상속하고 이를 메서드로 캡슐화하는 것입니다. ECMAScript5 환경은 지원하지 않으므로 번역되어 성능이 저하됩니다.
F.prototype=superCtor.prototype;
ctor.prototype=newF()
ctor.prototype.constructor=ctor;
마지막 매개변수가 현재 클래스의 메서드 선언이라는 점을 제외하면 다른 매개변수는 상위 클래스에서 상속되어 순환 상속이 필요하지만 여기에서의 처리는 비교적 간단하고 덮어쓰기가 포함되지 않습니다. 직접 추가할 수 있습니다.
*함수 상속.(node.js)
*
*@paramctorsubclass'sconstructor.
*@paramsuperctorsuperclass의 생성자입니다.
*/
varinherits=function(ctor,superCtor){
//부모 클래스를 명시적으로 지정
ctor.super_=superCtor;
//ECMAScript5 프로토타입 상속 및 역참조
if(Object.create){
ctor.prototype=Object.create(superCtor.prototype,{
생성자:{
값:ctor,
열거 가능:false,
쓰기 가능 :true,
configurable:true
}
});
}else{
//Object.create 메서드 없이 원활한 성능 저하
functionF(){}; .prototype=superCtor.prototype;
ctor.prototype=newF();
ctor.prototype.constructor=ctor;
}
}; 🎜>returnfunction(){
//마지막 매개변수는 새 클래스 메서드, 특성 및 생성자 선언입니다.
varsubClazz=arguments[arguments.length-1]||function(){}; 초기화는 생성자이고 그렇지 않으면 생성자는 빈 함수입니다.
varfn=subClazz.initialize==null?function(){}:subClazz.initialize;
//마지막 매개변수를 제외하고 클래스를 상속하면 더 많은 상속이 가능합니다. 확장 메서드로도 사용 가능
for(varindex=0;index
}
// 메서드 새로운 클래스 구현
for(varpropinsubClazz){
if(prop=="initialize"){
continue;
}
fn.prototype[prop]=subClazz[prop]
}
returnfn;
}
})()
다음 예를 참조하세요.
복사 코드
코드는 다음과 같습니다.
this.name=name
},
/**
*건축자.
*
*@paramname고양이 이름
*/
eat:function(){
alert (this. name "iseatingfish.");
}
})
/**
*먹기 기능.
*/
varBlackCat=Class(Cat,{
/**
*BlackCat 클래스의 정의.
*/
initialize:function(name,age){
//calltheconstructorofsuperclass.
BlackCat.super_.call(this,name)
this.age=age
} 🎜>/ **
*건축자.
*
*@paramname고양이 이름.
*@paramageCat'sage.
*/
eat:function(){
alert(this.name "(" this.age ")iseatingdog.")
}
});
/**
*먹기 기능.
*/
varBlackFatCat=Class(BlackCat,{
/**
*BlackFatCat 클래스의 정의입니다.
*@paramweightCat'sweight.
*/
초기화:함수(이름, age,weight ){
//calltheconstructorofsuperclass.
BlackFatCat.super_.call(this,name,age)
this.weight=weight;
/**
*건축자.
*
*@paramname고양이 이름.
*@paramageCat'sage.
*@paramweightCat의 체중입니다.
*/
eat:function(){
alert(this.name "(" this.age ")iseatingdog.Myweight:" this.weight)
}
}); >/* *
*먹기 기능.
*/
varDog=Class({});
varcat=newBlackFatCat("John",24,"100kg")
cat.eat(); //true
alert(catinstanceofCat);
//true
alert(catinstanceofBlackCat);//true
alert(catinstanceofBlackFatCat)
//true
alert( cat.constructor ===BlackFatCat);
//false
alert(catinstanceofDog);
mootools 클래스의 소스 코드 분석 라이브러리는 여기에서 볼 수 있습니다: http://www.cnblogs.com/hmking/archive/2011/09/30/2196504.html
구체적인 사용법 보기:
a 새 클래스 만들기
코드 복사
varCat=newClass({
initialize:function(name ){
this.name=name ;
}
})
b、繼承的實作
varAnimal=Class( {
initialize:function(age){
this.age=age;
}
});
varCat=newClass({
Extends:Animal,
initialize function(name,age){
this.parent(age);//callsinitalizemethodofAnimalclass
this.name=name;
}
});
varmyCat=newCat('M)'icia, 20);
alert(myCat.name);//alerts'Micia'.
alert(myCat.age);//alerts20.
c、擴充類別的實作
varAnimal=newClass({
varAnimal=newClass({
varAnimal=newClass({
this.age=age;
}
});
varCat=newClass({
Implements:Animal,
setName:function(name){
this .name=name
}); varmyAnimal=newCat(20); myAnimal.setName('Micia');
alert(myAnimal.name);//alerts' Micia'.
複製程式碼
程式碼如下:
//建立類別Person
varPerson=Class(object,{
Create:function(reate name,age){
this.name=name;
this.age=age;
},
SayHello:function(){
}
});
複製程式碼
程式碼如下:
//Employee繼承Person
varEmployee=Class(Person,{
Create:function(name,age,salary){
Person.Create.call(this,name,age);
//呼叫基底類別的建構子
this.salary=salary;
},
ShowMeTheMoney:function(){
alert(this.name "$" this.salary);
}
});
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();
程式碼如下:
//建立類別的函數,用於宣告類別及繼承關係
functionClass(aBaseClass,aClassDefine){
//建立類別的臨時函數殼
functionclass_(){
this.Type=aBaseClass;
//我們給每一個類別約定一個Type屬性,引用其繼承的類別
for(varmemberinaClassDefine)
this[member]=aClassDefine[member];
//複製類別的全部定義到目前建立的類別
};
class_.prototype=aBaseClass;
returnnewclass_();
};
//建立物件的函數,用於任意類別的物件建立
functionNew(aClass,aParams){
//建立物件的暫存函數殼
functionnew_(){
this.Type=aClass;
//我們也給予每個物件約定一個Type屬性,據此可以存取到物件所屬的類別
if(aClass.Create)
aClass.Create.apply(this,aParams);
//我們約定所有類別的建構子都叫做Create,這和DELPHI比較相似
};
new_.prototype=aClass;
};
由於寫的比較籠統,可能有很多地方沒有解析到,也可能有不準確的地方,還望指正。 看完上面幾種解析,相資訊自己也可以寫出一個自己的封裝類別庫出來,至於,怎麼實現看個人喜好了。但基本的思都是一樣的基於原型的繼承方式和循環拷貝新方法。 原文出自:穆乙 http://www.cnblogs.com/pigtail/

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

類別和方法的概念和實例類別(Class):用來描述具有相同的屬性和方法的物件的集合。它定義了該集合中每個物件所共有的屬性和方法。物件是類別的實例。方法:類別中定義的函數。類別的建構方法__init__():類別有一個名為init()的特殊方法(建構方法),該方法在類別實例化時會自動呼叫。實例變數:在類別的宣告中,屬性是用變數來表示的,這種變數就稱為實例變量,實例變數就是用self修飾的變數。實例化:建立一個類別的實例,類別的具體物件。繼承:即一個派生類別(derivedclass)繼承基底類別(baseclass)的

class是python中的一個關鍵字,用來定義一個類,定義類別的方法:class後面加一個空格然後加類名;類名規則:首字母大寫,如果多個單字用駝峰命名法,如【class Dog()】。

jQuery是一種經典的JavaScript庫,被廣泛應用於網頁開發中,它簡化了在網頁上處理事件、操作DOM元素和執行動畫等操作。在使用jQuery時,常會遇到需要取代元素的class名稱的情況,本文將介紹一些實用的方法,以及具體的程式碼範例。 1.使用removeClass()和addClass()方法jQuery提供了removeClass()方法來刪除

在編寫PHP程式碼時,使用類別(Class)是一個非常常見的做法。透過使用類,我們可以將相關的功能和資料封裝在一個單獨的單元中,使程式碼更加清晰、易於閱讀和易於維護。本文將詳細介紹PHPClass的用法,並提供具體的程式碼範例,幫助讀者更好地理解如何在實際專案中應用類別來優化程式碼。 1.建立和使用類別在PHP中,可以使用關鍵字class來定義一個類,並在類別中定義屬性和方法。

Vue報錯:無法正確使用v-bind綁定class和style,怎麼解決?在Vue開發中,我們常常會用到v-bind指令來動態綁定class和style,但是有時候我們可能會遇到一些問題,如無法正確使用v-bind綁定class和style。在本篇文章中,我將為你解釋這個問題的原因,並提供解決方案。首先,讓我們先來了解v-bind指令。 v-bind用於將V

jquery判斷元素是否有class的方法:1、透過「hasClass('classname')」方法判斷元素是否具有某個class;2、透過「is('.classname')」方法判斷元素是否具有某個class。
![解決'[Vue warn]: v-bind:class/ :class”錯誤的方法](https://img.php.cn/upload/article/000/465/014/169300902772563.jpg?x-oss-process=image/resize,m_fill,h_207,w_330)
解決「[Vuewarn]:v-bind:class/:class」錯誤的方法在使用Vue開發過程中,我們常常會遇到一些錯誤提示,其中一個常見的錯誤就是「[Vuewarn]:v-bind:class /:class”錯誤。這個錯誤提示通常出現在我們使用v-bind:class或:class屬性時,表示Vue無法正確解析我們設定的class值。那麼,如

背景最近針對公司框架進行關鍵業務代碼進行加密處理,防止透過jd-gui等反編譯工具能夠輕鬆還原工程代碼,相關混淆方案配置使用比較複雜且針對springboot項目問題較多,所以針對class文件加密再通過自訂的classloder進行解密加載,此方案並不是絕對安全,只是加大反編譯的困難程度,防君子不防小人,整體加密保護流程圖如下圖所示maven插件加密使用自訂maven插件對編譯後指定的class檔案進行加密,加密後的class檔案拷貝到指定路徑,這裡是儲存到resource/corecla
