欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript的面向?qū)ο缶幊袒A(chǔ)

 更新時(shí)間:2015年08月13日 11:22:07   作者:libuchao  
這篇文章主要介紹了JavaScript的面向?qū)ο缶幊袒A(chǔ),是JavaScript入門(mén)學(xué)習(xí)中的重要知識(shí)概念,需要的朋友可以參考下

重新認(rèn)識(shí)面向?qū)ο?br /> 為了說(shuō)明 JavaScript 是一門(mén)徹底的面向?qū)ο蟮恼Z(yǔ)言,首先有必要從面向?qū)ο蟮母拍钪?, 探討一下面向?qū)ο笾械膸讉€(gè)概念:

  1. 一切事物皆對(duì)象
  2. 對(duì)象具有封裝和繼承特性
  3. 對(duì)象與對(duì)象之間使用消息通信,各自存在信息隱藏

以這三點(diǎn)做為依據(jù),C++ 是半面向?qū)ο蟀朊嫦蜻^(guò)程語(yǔ)言,因?yàn)?,雖然他實(shí)現(xiàn)了類(lèi)的封裝、繼承和多態(tài),但存在非對(duì)象性質(zhì)的全局函數(shù)和變量。Java、C# 是完全的面向?qū)ο笳Z(yǔ)言,它們通過(guò)類(lèi)的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。但這里函數(shù)本身是一個(gè)過(guò)程,只是依附在某個(gè)類(lèi)上。

然而,面向?qū)ο髢H僅是一個(gè)概念或者編程思想而已,它不應(yīng)該依賴(lài)于某個(gè)語(yǔ)言存在。比如 Java 采用面向?qū)ο笏枷霕?gòu)造其語(yǔ)言,它實(shí)現(xiàn)了類(lèi)、繼承、派生、多態(tài)、接口等機(jī)制。但是這些機(jī)制,只是實(shí)現(xiàn)面向?qū)ο缶幊痰囊环N手段,而非必須。換言之,一門(mén)語(yǔ)言可以根據(jù)其自身特性選擇合適的方式來(lái)實(shí)現(xiàn)面向?qū)ο?。所以,由于大多?shù)程序員首先學(xué)習(xí)或者使用的是類(lèi)似 Java、C++ 等高級(jí)編譯型語(yǔ)言(Java 雖然是半編譯半解釋?zhuān)话阕鰹榫幾g型來(lái)講解),因而先入為主地接受了“類(lèi)”這個(gè)面向?qū)ο髮?shí)現(xiàn)方式,從而在學(xué)習(xí)腳本語(yǔ)言的時(shí)候,習(xí)慣性地用類(lèi)式面向?qū)ο笳Z(yǔ)言中的概念來(lái)判斷該語(yǔ)言是否是面向?qū)ο笳Z(yǔ)言,或者是否具備面向?qū)ο筇匦?。這也是阻礙程序員深入學(xué)習(xí)并掌握 JavaScript 的重要原因之一。
實(shí)際上,JavaScript 語(yǔ)言是通過(guò)一種叫做 原型(prototype)的方式來(lái)實(shí)現(xiàn)面向?qū)ο缶幊痰摹O旅婢蛠?lái)討論 基于類(lèi)的(class-based)面向?qū)ο蠛?基于原型的 (prototype-based) 面向?qū)ο筮@兩種方式在構(gòu)造客觀世界的方式上的差別。
基于類(lèi)的面向?qū)ο蠛突谠偷拿嫦驅(qū)ο蠓绞奖容^
在基于類(lèi)的面向?qū)ο蠓绞街?,?duì)象(object)依靠 類(lèi)(class)來(lái)產(chǎn)生。而在基于原型的面向?qū)ο蠓绞街?,?duì)象(object)則是依靠 構(gòu)造器(constructor)利用 原型(prototype)構(gòu)造出來(lái)的。舉個(gè)客觀世界的例子來(lái)說(shuō)明二種方式認(rèn)知的差異。例如工廠造一輛車(chē),一方面,工人必須參照一張工程圖紙,設(shè)計(jì)規(guī)定這輛車(chē)應(yīng)該如何制造。這里的工程圖紙就好比是語(yǔ)言中的 類(lèi) (class),而車(chē)就是按照這個(gè) 類(lèi)(class)制造出來(lái)的;另一方面,工人和機(jī)器 ( 相當(dāng)于 constructor) 利用各種零部件如發(fā)動(dòng)機(jī),輪胎,方向盤(pán) ( 相當(dāng)于 prototype 的各個(gè)屬性 ) 將汽車(chē)構(gòu)造出來(lái)。
事實(shí)上關(guān)于這兩種方式誰(shuí)更為徹底地表達(dá)了面向?qū)ο蟮乃枷?,目前尚有?zhēng)論。但筆者認(rèn)為原型式面向?qū)ο笫且环N更為徹底的面向?qū)ο蠓绞?,理由如下?br /> 首先,客觀世界中的對(duì)象的產(chǎn)生都是其它實(shí)物對(duì)象構(gòu)造的結(jié)果,而抽象的“圖紙”是不能產(chǎn)生“汽車(chē)”的,也就是說(shuō),類(lèi)是一個(gè)抽象概念而并非實(shí)體,而對(duì)象的產(chǎn)生是一個(gè)實(shí)體的產(chǎn)生;
其次,按照一切事物皆對(duì)象這個(gè)最基本的面向?qū)ο蟮姆▌t來(lái)看,類(lèi) (class) 本身并不是一個(gè)對(duì)象,然而原型方式中的構(gòu)造器 (constructor) 和原型 (prototype) 本身也是其他對(duì)象通過(guò)原型方式構(gòu)造出來(lái)的對(duì)象。
再次,在類(lèi)式面向?qū)ο笳Z(yǔ)言中,對(duì)象的狀態(tài) (state) 由對(duì)象實(shí)例 (instance) 所持有,對(duì)象的行為方法 (method) 則由聲明該對(duì)象的類(lèi)所持有,并且只有對(duì)象的結(jié)構(gòu)和方法能夠被繼承;而在原型式面向?qū)ο笳Z(yǔ)言中,對(duì)象的行為、狀態(tài)都屬于對(duì)象本身,并且能夠一起被繼承(參考資源),這也更貼近客觀實(shí)際。
最后,類(lèi)式面向?qū)ο笳Z(yǔ)言比如 Java,為了彌補(bǔ)無(wú)法使用面向過(guò)程語(yǔ)言中全局函數(shù)和變量的不便,允許在類(lèi)中聲明靜態(tài) (static) 屬性和靜態(tài)方法。而實(shí)際上,客觀世界不存在所謂靜態(tài)概念,因?yàn)橐磺惺挛锝詫?duì)象!而在原型式面向?qū)ο笳Z(yǔ)言中,除內(nèi)建對(duì)象 (build-in object) 外,不允許全局對(duì)象、方法或者屬性的存在,也沒(méi)有靜態(tài)概念。所有語(yǔ)言元素 (primitive) 必須依賴(lài)對(duì)象存在。但由于函數(shù)式語(yǔ)言的特點(diǎn),語(yǔ)言元素所依賴(lài)的對(duì)象是隨著運(yùn)行時(shí) (runtime) 上下文 (context) 變化而變化的,具體體現(xiàn)在 this 指針的變化。正是這種特點(diǎn)更貼近 “萬(wàn)物皆有所屬,宇宙乃萬(wàn)物生存之根本”的自然觀點(diǎn)。


JavaScript 面向?qū)ο蠡A(chǔ)知識(shí)

雖然 JavaScript 本身是沒(méi)有類(lèi)的概念,但它仍然有面向?qū)ο蟮奶匦?,雖然和一般常見(jiàn)的面向?qū)ο笳Z(yǔ)言有所差異。

簡(jiǎn)單的創(chuàng)建一個(gè)對(duì)象的方法如下:

function myObject() {

};

JavaScript 中創(chuàng)建對(duì)象的方法一般來(lái)說(shuō)有兩種:函數(shù)構(gòu)造法和字面量法,上面這種屬函數(shù)構(gòu)造法。下面是一個(gè)字面量法的例子:

var myObject = {

};

如果僅僅需要一個(gè)對(duì)象,而不需要對(duì)象的其它實(shí)例的情況下,推薦用字面量法。如果需要對(duì)象的多個(gè)實(shí)例,則推薦函數(shù)構(gòu)造法。
定義屬性和方法

函數(shù)構(gòu)造法:

function myObject() {
 this.iAm = 'an object';

 this.whatAmI = function() {
 console.log('I am ' + this.iAm);
 };
};

字面量法:

var myObject = {
 iAm : 'an object',

 whatAmI : function() {
 console.log('I am ' + this.iAm);
 }
};

以上兩種方法創(chuàng)建的對(duì)象中,都有一個(gè)名為 “iAm” 的屬性,還有一個(gè)名為 “whatAmI” 的方法。屬性是對(duì)象中的變量,方法則是對(duì)象中的函數(shù)。

如何獲取屬性及調(diào)用方法:

var w = myObject.iAm;

myObject.whatAmI();

調(diào)用方法的時(shí)候后面一定要加上括號(hào),如果不加括號(hào),那么它只是返回方法的引用而已。
兩種創(chuàng)建對(duì)象方法的區(qū)別

  •     函數(shù)構(gòu)造法里面定義屬性和方法的時(shí)候,都要用前綴 this,字面量法不需要。
  •     函數(shù)構(gòu)造法給屬性和方法賦值的時(shí)候用的是 =,字面量法用的是 : 。
  •     如果有多個(gè)屬性或方法,函數(shù)構(gòu)造法里面用 ; 隔開(kāi),字面量法用 , 隔開(kāi)。

對(duì)于字面量法創(chuàng)建的對(duì)象,可以直接用對(duì)象的引用調(diào)用其屬性或方法:

myObject.whatAmI();

而對(duì)于函數(shù)構(gòu)造法而言,需要?jiǎng)?chuàng)建對(duì)象的實(shí)例,才能調(diào)用其屬性或方法:

var myNewObject = new myObject();
myNewObject.whatAmI();

使用構(gòu)造函數(shù)

現(xiàn)在再來(lái)回歸一下之前的函數(shù)構(gòu)造法:

function myObject() {
 this.iAm = 'an object';
 this.whatAmI = function() {
 console.log('I am ' + this.iAm);
 };
};

其實(shí)它看起來(lái)就是個(gè)函數(shù),既然是函數(shù),能不能給它傳參數(shù)呢?將代碼再稍作修改:

function myObject(what) {
 this.iAm = what;
 this.whatAmI = function(language) {
 console.log('I am ' + this.iAm + ' of the ' + language + ' language');
 };
};

再將對(duì)象實(shí)例化,并傳入?yún)?shù):

var myNewObject = new myObject('an object');
myNewObject.whatAmI('JavaScript');

程序最終輸出 I am an object of the JavaScript language。
兩種創(chuàng)建對(duì)象的方法,我該用哪種?

對(duì)于字面量方法而言,因?yàn)樗恍枰獙?shí)例化,所以如果修改了某對(duì)象的值,那么這個(gè)對(duì)象的值就永久地被修改了,其它任何地方再訪問(wèn),都是修改后的值。而對(duì)于函數(shù)構(gòu)造法而言,修改值的時(shí)候是修改其實(shí)例的值,它可以實(shí)例化 N 個(gè)對(duì)象出來(lái),每個(gè)對(duì)象都可以擁有自己不同的值,而且互不干擾。比較以下幾段代碼。

先看字面量法:

var myObjectLiteral = {
 myProperty : 'this is a property'
};

console.log(myObjectLiteral.myProperty); // log 'this is a property'

myObjectLiteral.myProperty = 'this is a new property';

console.log(myObjectLiteral.myProperty); // log 'this is a new property'

即便創(chuàng)建了一個(gè)新的變量指向這個(gè)對(duì)象,結(jié)果還是一樣的:

var myObjectLiteral = {
 myProperty : 'this is a property'
};

console.log(myObjectLiteral.myProperty); // log 'this is a property'

var sameObject = myObjectLiteral;

myObjectLiteral.myProperty = 'this is a new property';

console.log(sameObject.myProperty); // log 'this is a new property'

再看函數(shù)構(gòu)造法:

// 用函數(shù)構(gòu)造法
var myObjectConstructor = function() {
   this.myProperty = 'this is a property'
};

// 實(shí)例化一個(gè)對(duì)象
var constructorOne = new myObjectConstructor();

// 實(shí)例化第二個(gè)對(duì)象
var constructorTwo = new myObjectConstructor();

// 輸出
console.log(constructorOne.myProperty); // log 'this is a property'

// 輸出
console.log(constructorTwo.myProperty); // log 'this is a property'

和預(yù)期一樣,兩個(gè)對(duì)象的屬性值是一樣的。如果修個(gè)其中一個(gè)對(duì)象的值呢?

// 用函數(shù)構(gòu)造法
var myObjectConstructor = function() {
 this.myProperty = 'this is a property';
};

// 實(shí)例化一個(gè)對(duì)象
var constructorOne = new myObjectConstructor();

// 修改對(duì)象的屬性
constructorOne.myProperty = 'this is a new property';

// 實(shí)例化第二個(gè)對(duì)象
var constructorTwo = new myObjectConstructor();

// 輸出
alert(constructorOne.myProperty); // log 'this is a new property'

// 輸出
alert(constructorTwo.myProperty); // log 'this is a property'

可以看到,用函數(shù)構(gòu)造法實(shí)例化出來(lái)的不同對(duì)象,相互是獨(dú)立的,可以各自擁有不同的值。所以說(shuō),到底用哪種方法來(lái)創(chuàng)建對(duì)象,需取決于各自實(shí)際情況。

相關(guān)文章

最新評(píng)論