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