如果你是一個(gè)Web開(kāi)發(fā)者而且與我來(lái)自同一個(gè)地方,你也許在你的Web頁(yè)面中使用過(guò)相當多的Javascript,大部分用來(lái)作用戶(hù)界面(UI)的粘合。
直到現在,我才知道Javascript具有比我過(guò)去使用的更多的面向對象能力,只是我沒(méi)有如我所需的去使用它。當瀏覽器開(kāi)始支持更標準的Javascript和DOM的功能集時(shí),要為客戶(hù)端上的運行而編寫(xiě)更復雜和多功能的代碼就變得可行了。它助長(cháng)了AJAX現象的產(chǎn)生。
當我們都開(kāi)始學(xué)習它適合編寫(xiě)什么酷的AJAX應用時(shí),我們開(kāi)始關(guān)注到我們過(guò)去知道的Javascript不過(guò)只是冰山一角而已。我們現在知道Javascript不僅僅被用于象輸入校驗等簡(jiǎn)單的用戶(hù)界面雜務(wù)和其他瑣碎任務(wù)?,F在的客戶(hù)端代碼更高級和分層,更象一個(gè)真正的桌面應用或一個(gè)客戶(hù)端-服務(wù)器的富客戶(hù)端。我們在其中看到了過(guò)去僅在服務(wù)器端的代碼中見(jiàn)到的類(lèi)庫、對象模型、繼承關(guān)系、模式和許多其他的東西。
突然在我們能講到的許多方面被放到了比以前更高的位置。要為新的Web編寫(xiě)應用,我們必需提高我們的Javascript水平來(lái)跟上它而且要更加熟練。假如你嘗試運用許多現有的javascript庫,如:Prototype.js、Scriptaculous、moo.fx、Behaviour、YUI等,你最終會(huì )發(fā)現自己要閱讀JS代碼?;蛟S因為你想要學(xué)習它們如何實(shí)現,或因為你的好奇,或通常因為那是知道如何使用它的唯一辦法,大多數這些庫象是不太注重文檔。無(wú)論個(gè)案會(huì )是什么,假如你之前不了解那樣的東西,你將要面對一些引起恐慌的外部技術(shù)。
本文的目的正好是解說(shuō)許多我們還不熟悉的構造類(lèi)型。
Javascript對象表示法(JSON),是圍繞AJAX主題突然出現的一個(gè)新的時(shí)髦詞。JSON,簡(jiǎn)單的說(shuō)就是一種在Javascript中定義對象的方法。讓我們馬上來(lái)看看一個(gè)實(shí)例并體會(huì )它如何簡(jiǎn)單。
var myPet = { color: 'black', leg_count: 4, communicate: function(repeatCount){for(i=0;i<repeatCount;i++) alert('Woof!');} };
就讓我們加入些許格式讓它看起來(lái)象我們平常所認識的那樣:
var myPet ={color: 'black',legCount: 4,communicate: function(repeatCount){for(i=0;i<repeatCount;i++)alert('Woof!');}};
在這我們創(chuàng )建了一個(gè)帶兩個(gè)屬性(color和legCount)和一個(gè)方法(communicate)的對象引用。不難發(fā)現,該對象的屬性和方法用一個(gè)逗號區隔的列表來(lái)定義。每個(gè)成員通過(guò)名稱(chēng)來(lái)引入,接著(zhù)是冒號和定義。對于屬性來(lái)說(shuō)很容易,僅僅是屬性值。方法通過(guò)指派一個(gè)匿名函數來(lái)創(chuàng )建,我們下面會(huì )更好地說(shuō)明。在該對象被創(chuàng )建并指派給變量myPet之后,我們可以如下使用它:
alert('my pet is ' + myPet.color);alert('my pet has ' + myPet.legCount + ' legs');//if you are a dog, bark three times:myPet.communicate(3);
You'll see JSON used pretty much everywhere in JS these days, as arguments to functions, as return values, as server responses (in strings,) etc.
對于開(kāi)發(fā)者來(lái)說(shuō)這可能與眾不同,但在JS中一個(gè)函數也是一個(gè)對象。你可以象參數一樣把一個(gè)函數傳送給另一個(gè)函數,就象你可以傳送一個(gè)字符串一樣。這些被廣泛應用而且非常便利。
看看這個(gè)實(shí)例。我們將把函數傳送到另一個(gè)使用它們的函數去。
var myDog ={bark: function(){alert('Woof!');}}; var myCat ={meow: function(){alert('I am a lazy cat. I will not meow for you.');}}; function annoyThePet(petFunction){//let's see what the pet can dopetFunction();} //annoy the dog:annoyThePet(myDog.bark);//annoy the cat:annoyThePet(myCat.meow);
注意,我們把沒(méi)有添加"()"的myDog.bark和myCat.meow傳送給它們。假如我們那樣做了,我們不是傳送函數,而是調用那些方法并傳送它們的返回值,這里的兩個(gè)個(gè)案中都未定義。
要是你想另我的懶貓起來(lái)嗥叫,你可以簡(jiǎn)單地這樣做:
myCat.meow = myDog.bark;myCat.meow(); //alerts 'Woof!'
在JS中下列兩行做了同樣的事。
var a = new Array();var b = [];
正如我確定你已經(jīng)知道的那樣,你可以通過(guò)使用方括號在一個(gè)數組中訪(fǎng)問(wèn)個(gè)別項目:
var a = ['first', 'second', 'third'];var v1 = a[0];var v2 = a[1];var v3 = a[2];
但你還不限于數字索引。你可以通過(guò)使用它的名字以字符串來(lái)訪(fǎng)問(wèn)一個(gè)JS對象的任何成員。下面的例子創(chuàng )建了一個(gè)空對象,并通過(guò)名字加入了一些成員。
var obj = {}; //new, empty objectobj['member_1'] = 'this is the member value';obj['flag_2'] = false;obj['some_function'] = function(){ /* do something */};
上述代碼的作用與下面的相同:
var obj ={member_1:'this is the member value',flag_2: false,some_function: function(){ /* do something */}};
在許多情形下,在JS中對象的概念和關(guān)聯(lián)的數組(雜湊)沒(méi)有區別。下面兩行代碼都做了同樣的事情。
obj.some_function();obj['some_function']();
面向對象編程語(yǔ)言的巨大力量來(lái)源于類(lèi)的使用。我不認為僅應用我之前使用其他語(yǔ)言的經(jīng)驗就能推測出在JS中如何定義類(lèi)。這由你自己來(lái)判斷。
//defining a new class called Petvar Pet = function(petName, age){this.name = petName;this.age = age;}; //let's create an object of the Pet classvar famousDog = new Pet('Santa\'s Little Helper', 15);alert('This pet is called ' + famousDog.name);
讓我們看看如何加入一個(gè)方法到我們的Pet類(lèi)。我們將使用所有類(lèi)都具有的prototype屬性。prototype屬性是一個(gè)包含任何對象的類(lèi)會(huì )具有的所有成員的對象。甚至默認的JS類(lèi),如String、Number和Date擁有一個(gè)的prototype對象,它能讓我們可以添加方法和屬性并使那個(gè)類(lèi)的任何對象自動(dòng)獲取這個(gè)新成員。
Pet.prototype.communicate = function(){alert('I do not know what I should say, but my name is ' + this.name);};
那就是一個(gè)類(lèi)似于prototype.js的庫會(huì )派上用場(chǎng)的時(shí)候。如果我們使用prototype.js,我們能使我們的代碼看起來(lái)更清晰(至少在我看來(lái)是這樣)。
var Pet = Class.create();Pet.prototype ={//our 'constructor'initialize: function(petName, age){this.name = petName;this.age = age;}, communicate: function(){alert('I do not know what I should say, but my name is ' + this.name);}};
假如你從來(lái)沒(méi)有接觸過(guò)支持閉合的語(yǔ)言,你也許會(huì )發(fā)現下面的慣用法太令人震驚了。
var myArray = ['first', 'second', 'third'];myArray.each( function(item, index){alert('The item in the position #' + index + ' is:' + item);});
哇!在你斷定我已經(jīng)離題太遠并且想轉去比這篇更好點(diǎn)的文章之前,讓我們在這解釋一下要繼續干些什么。
首先,在上述實(shí)例中我們使用了prototype.js庫,它添加了each函數到Array類(lèi)。該each函數接到一個(gè)函數對象的參數。這個(gè)函數對于數組中的每個(gè)項目都將被依次調用一次,對于當前項目調用時(shí)傳送兩個(gè)參數,item和index。讓我們稱(chēng)這個(gè)函數為iterator函數。我們也能象這樣編寫(xiě)代碼:
function myIterator(item, index){alert('The item in the position #' + index + ' is:' + item);} var myArray = ['first', 'second', 'third'];myArray.each( myIterator );
我們不會(huì )象那些學(xué)校里的那些天真孩子那樣做的,對吧?雖然更嚴格地說(shuō),后面的形式更易于理解但導致我們要進(jìn)入代碼中四處找尋myIterator函數。最好在它調用的同一個(gè)地方那里有迭代函數的邏輯。在本案例中,我們也不會(huì )在其他任何地方需要迭代函數,所以我們無(wú)損地把它轉化成一個(gè)匿名函數。
當使用JS開(kāi)始編寫(xiě)我們的代碼時(shí),我們最普遍的一個(gè)麻煩就是this關(guān)鍵字的使用。它是一個(gè)真正的牽絆。
就象我們之前提及的那樣,在JS中一個(gè)函數也是一個(gè)對象,而且有時(shí)候我們不注意我們正在傳出一個(gè)函數。
拿這小段代碼舉個(gè)例:
function buttonClicked(){alert('button ' + this.id + ' was clicked');} var myButton = document.getElementById('someButtonID');var myButton2 = document.getElementById('someOtherButtonID');myButton.onclick = buttonClicked;myButton2.onclick = buttonClicked;
由于buttonClicked函數在任何對象之外被定義,我們也許以為this關(guān)鍵字會(huì )包含一個(gè)window或document對象(假設這些代碼位于一個(gè)在瀏覽器中被瀏覽的HTML頁(yè)面中間)的引用。
但是當我們運行這段代碼時(shí),我們看到它如愿工作并顯示被點(diǎn)擊按鈕的id。究竟其中發(fā)生了什么另我們使每個(gè)按鈕的onclick方法包含buttonClicked對象引用,而無(wú)論之前那里有什么?,F在無(wú)論按鈕什么時(shí)候被點(diǎn)擊,瀏覽器都會(huì )運行一些類(lèi)似下行的東西:
myButton.onclick();
那畢竟不是這么混亂,是吧?只要你了解有別的對象要進(jìn)行處理并想在這些對象的事件上,如點(diǎn)擊按鈕,進(jìn)行什么行動(dòng)后發(fā)生了什么就行了。
var myHelper ={formFields: [ ],emptyAllFields: function(){for(i=0; i < this.formFields.length; i++){var elementID = this.formFields[i];var field = document.getElementById(elementID);field.value = '';}}}; //tell which form fields we want to work withmyHelper.formFields.push('txtName');myHelper.formFields.push('txtEmail');myHelper.formFields.push('txtAddress'); //clearing the text boxes:myHelper.emptyAllFields(); var clearButton = document.getElementById('btnClear');clearButton.onclick = myHelper.emptyAllFields;
因此你想:好了,現在我可以在我的頁(yè)面上點(diǎn)擊Clear按鈕,那三個(gè)文本框就將被清空。然后你嘗試點(diǎn)擊該按鈕后僅得到一個(gè)運行時(shí)錯誤。該錯誤將涉及(猜猜是什么?)this關(guān)鍵字。該問(wèn)題是this.formFields沒(méi)被定義即便this包含了一個(gè)到按鈕的引用,那正是現在所發(fā)生的。一個(gè)快速的解決方案是重寫(xiě)我們最后一行的代碼。
clearButton.onclick = function(){myHelper.emptyAllFields();};
我們創(chuàng )建一個(gè)全新的函數,那種方法在協(xié)助對象的場(chǎng)景中調用了我們的協(xié)助方法。
聯(lián)系客服