李勝
(西南石油大學(xué),四川 成都 610500)
在實(shí)際操作過(guò)程中,很多程序員熟練掌握各種框架設(shè)計(jì),但是對(duì)代碼組織卻不盡理想,這是因?yàn)楹芏喑绦蛟O(shè)計(jì)人員對(duì)JavaScript 的語(yǔ)言特性了解不夠透徹,關(guān)于JavaScript面對(duì)對(duì)象語(yǔ)言特性的參考文獻(xiàn)少之又少,有些文獻(xiàn)提出的JavaScript 面向?qū)ο蟮挠^點(diǎn)理解的還有所偏差。基于此,本研究將重點(diǎn)針對(duì)如何真正理解JavaScript 面向?qū)ο笳Z(yǔ)言特性展開(kāi)討論,結(jié)合JavaScript 自身的特點(diǎn)對(duì)其面向?qū)ο筇匦赃M(jìn)行分析,以提高程序設(shè)計(jì)的設(shè)計(jì)標(biāo)準(zhǔn)。
封裝、繼承、多態(tài)作為面向?qū)ο蠡镜恼Z(yǔ)言特性,對(duì)事物的具體結(jié)構(gòu)進(jìn)行描述以幫助人們能夠更好地理解知識(shí),將復(fù)雜的知識(shí)形象化,其中,封裝的本質(zhì)是為了隱藏信息,將對(duì)象的屬性和方法組成整體,通過(guò)傳遞消息的方式訪問(wèn)對(duì)象;繼承則是在類(lèi)的基礎(chǔ)上生成新的類(lèi),以實(shí)現(xiàn)代碼的操作;多態(tài)則是通過(guò)調(diào)用的方式呈現(xiàn)出不同的對(duì)象,讓程序變得更加簡(jiǎn)潔。
除了這三類(lèi)基本的語(yǔ)言特性外,還有對(duì)象、屬性、行為和類(lèi),這些都是編程語(yǔ)言中的基礎(chǔ)特性。在面向?qū)ο蟮木幊趟枷胫校瑢?duì)象的作用非常重要,對(duì)象在程序設(shè)計(jì)語(yǔ)言中是客觀事物的表現(xiàn)形式;屬性是事物的靜態(tài)特征;行為是事物的動(dòng)作;類(lèi)是將相同屬性的對(duì)象進(jìn)行集合。類(lèi)更是一種模板,對(duì)象則是在類(lèi)這個(gè)模板中所創(chuàng)造出來(lái)的產(chǎn)物。
在基于類(lèi)的表達(dá)方式中,可以通過(guò)類(lèi)的方式創(chuàng)建多個(gè)屬性和行為,然后通過(guò)創(chuàng)建出來(lái)的屬性和行為對(duì)類(lèi)進(jìn)行表達(dá),在早期ECMAScirpt 中沒(méi)有對(duì)類(lèi)進(jìn)行闡述,ECMA-262 就是將對(duì)象定義成了無(wú)序?qū)傩运鶚?gòu)成的集合,并且該集合中有基本值和對(duì)象。當(dāng)JavaScript 轉(zhuǎn)給你包含了數(shù)值時(shí),數(shù)值可以表示數(shù)據(jù),也可以表示函數(shù)。當(dāng)表示數(shù)據(jù)時(shí),是屬性,反之是行為。這種基于原型的面向?qū)ο蠓椒ㄖ饕峭ㄟ^(guò)構(gòu)造器的方式對(duì)相應(yīng)的對(duì)象進(jìn)行構(gòu)造,比如生產(chǎn)機(jī)動(dòng)車(chē),人為制造與機(jī)械制造的思維方式肯定有所不同,機(jī)械工程師會(huì)先將機(jī)動(dòng)車(chē)的圖紙?jiān)O(shè)計(jì)出來(lái),根據(jù)設(shè)計(jì)原型對(duì)制作工藝進(jìn)行詳細(xì)規(guī)定,工人們只需要按照?qǐng)D紙進(jìn)行生產(chǎn)即可。而使用程序設(shè)計(jì)如何表示,設(shè)計(jì)好的圖紙就好似面向?qū)ο笾械念?lèi),而機(jī)動(dòng)車(chē)就是這個(gè)類(lèi)中的對(duì)象,工人和機(jī)器就是利用各種零件將機(jī)動(dòng)車(chē)進(jìn)行制造,制造機(jī)動(dòng)車(chē)的零件就是面向?qū)ο笾械膶傩?,機(jī)器表示函數(shù)。
在實(shí)際的應(yīng)用中,任何一個(gè)對(duì)象的產(chǎn)生都會(huì)通過(guò)其他已經(jīng)存在的對(duì)象進(jìn)行結(jié)合,從而形成一個(gè)構(gòu)造的結(jié)果,單單依靠一張圖紙是無(wú)法設(shè)計(jì)出機(jī)動(dòng)車(chē)的。類(lèi)是一個(gè)抽象的概念,而對(duì)象是一個(gè)實(shí)際存在的物體,如果按照最基本的面向?qū)ο蟮脑瓌t進(jìn)行分析,類(lèi)不僅僅是一個(gè)對(duì)象。處于原型中的構(gòu)造器并不會(huì)構(gòu)造出對(duì)象,而是通過(guò)更加簡(jiǎn)單的方式表述對(duì)象,讓人們能夠?qū)@個(gè)世界報(bào)以更加客觀的態(tài)度,從而更好地體現(xiàn)出面向?qū)ο蟮乃枷?。在基于?lèi)的面相對(duì)性的語(yǔ)言中,對(duì)象是由一個(gè)個(gè)單獨(dú)的對(duì)象組成,而行為和方法都需要通過(guò)類(lèi)進(jìn)行聲明,讓類(lèi)獨(dú)自擁有。在繼承的過(guò)程中,對(duì)象有一個(gè)從屬關(guān)系,子類(lèi)對(duì)象只能繼承父類(lèi)對(duì)象。在基于原型的面向?qū)ο笳Z(yǔ)言中,對(duì)象包含了行為與屬性,并且能夠同時(shí)繼承對(duì)象與屬性,也更加符合事物的發(fā)展規(guī)律。因此,面向?qū)ο蟮木幊趟枷胫校梢詫?duì)類(lèi)進(jìn)行使用,同時(shí)還可以通過(guò)其他的方式對(duì)類(lèi)進(jìn)行表述。其中,JavaScript 就是一種非常合適的例子,在了解這一觀點(diǎn)后,需要通過(guò)實(shí)際的案例說(shuō)明JavaScript 如何實(shí)現(xiàn)面向?qū)ο蟮奶匦浴?/p>
封裝作為面向?qū)ο蟮闹匾匦灾唬饕淖饔檬轻槍?duì)開(kāi)發(fā)者,當(dāng)對(duì)象在公布外部接口后會(huì)隱藏內(nèi)部功能,從而起到保護(hù)私有數(shù)據(jù)的作用。JavaScript 既是一種無(wú)類(lèi)的語(yǔ)言,又是一種函數(shù)式語(yǔ)言,構(gòu)造函數(shù)需要使用一種新的操作方式創(chuàng)建對(duì)象,比如new 操作符,如果調(diào)用者沒(méi)有使用new 操作符,構(gòu)造函數(shù)會(huì)繼續(xù)執(zhí)行程序,并且不會(huì)出現(xiàn)報(bào)錯(cuò)。因此,在JavaScript 程序中構(gòu)造函數(shù)的首字母需要是大寫(xiě),強(qiáng)制提醒調(diào)用者進(jìn)行使用。針對(duì)構(gòu)造函數(shù)中存在的不足,可以使用函數(shù)化的形式表示對(duì)象,能夠避免操作中可能會(huì)出現(xiàn)的隱患,通過(guò)閉包的方式隱藏私有成員。通過(guò)一個(gè)具體的實(shí)例討論JavaScript 如何實(shí)現(xiàn)封裝特性:
var Book=function(id,name,price){
var num=1;
// 私有方法
function checkId(){};
// 特權(quán)方法
this.getName=function(){};
this.setPrice=function(){};
this.getName=function(){};
this.setPrice=function(){};
// 對(duì)像公有屬性
this.id=id;
// 對(duì)象公有方法
this.copy=function(){};
// 構(gòu)造器
this.setName(name);
this.setPrice(price);
}
類(lèi)的內(nèi)部this 中所定義的屬性和方法能夠被復(fù)制,并將類(lèi)的屬性和方法應(yīng)用在新的對(duì)象中,將其稱(chēng)為公有化,同時(shí)還可以訪問(wèn)私有的屬性和方法,這種方式就叫作特權(quán)方法。可以通過(guò)以下方式進(jìn)行調(diào)用:
var book=new Book(11, '設(shè)計(jì)模式', 50);
console.log(b.num); //undefined
console.log(b.id); //11
JavaScript 并不具備繼承的相關(guān)含義,同時(shí)也沒(méi)有對(duì)抽象類(lèi)的參數(shù)進(jìn)行定義,JavaScript 是通過(guò)語(yǔ)言的特性實(shí)現(xiàn)繼承的功能,JavaScript 支持多重繼承,實(shí)現(xiàn)繼承的方式有很多,比如類(lèi)式繼承、構(gòu)造函數(shù)繼承、組合繼承、原型式繼承、寄生式繼承、寄生組合式繼承、多繼承等。每一個(gè)類(lèi)有三部分組成,構(gòu)造函數(shù)內(nèi)、構(gòu)造函數(shù)外以及類(lèi)的原型。類(lèi)式繼承一般是通過(guò)子類(lèi)的原型而實(shí)現(xiàn)的,其中類(lèi)式繼承主要是通過(guò)子類(lèi)的原型prototype 對(duì)象實(shí)例化而實(shí)現(xiàn)的,如:
function Parent(name){this.name=name; }
Parent.prototype.say=function(){
console.log(this.name+'say');
};
function Child(name){
Parent.call(this, name);
}
Child.prototype.say=function(){
console.log('Child'+this.name+'say');
};
const child=new Child('Ben');
方法的重載和覆蓋可以實(shí)現(xiàn)面向?qū)ο蟮亩鄳B(tài)性,重載就是可以通過(guò)多種不同的方式實(shí)現(xiàn)相同的含義,并對(duì)參數(shù)的類(lèi)型進(jìn)行有效的識(shí)別,JavaScript 在定義函數(shù)時(shí)不需要對(duì)函數(shù)參數(shù)的類(lèi)型進(jìn)行識(shí)別,JavaScript 本身就支持重載。通過(guò)對(duì)傳遞的參數(shù)判斷執(zhí)行邏輯,實(shí)現(xiàn)一種多態(tài)處理機(jī)制,通過(guò)多態(tài)類(lèi)調(diào)用add 運(yùn)算方法,根據(jù)不同的參數(shù)進(jìn)行運(yùn)算。
function Add(){
// 無(wú)參數(shù)算法
function zero(){
return 0;
}
// 一個(gè)參數(shù)的算法
function one(num){
return 10+num;
}
// 兩個(gè)參數(shù)的算法
function two(num1, num2){
return num1+num2;
}
this.add=function(){
var args=arguments;
var len=args.length;
switch(len){
case 0:
return zero();
case 1:
return one(args[0]);
case 2:
return two(args[0], args[1]);
}
}
}
// 實(shí)例化
var A=new Add();
console.log(A.add()); //10
console.log(A.add(5)); //15
console.log(A.add(6, 7)); //13
傳統(tǒng)的基于類(lèi)的面向?qū)ο笏季S具有一定的理解難度,本文通過(guò)實(shí)例了解了面向?qū)ο蟪绦蛟O(shè)計(jì),深入分析了面向?qū)ο蟮恼Z(yǔ)言特性和編程,并對(duì)面向?qū)ο蟮奶匦赃M(jìn)行了闡述,簡(jiǎn)單實(shí)用,容易理解,具有非常高的靈活性。