日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

精通JavaScript--01面向对象JavaScript

發布時間:2025/5/22 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 精通JavaScript--01面向对象JavaScript 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JavaScript中什么是構造函數:http://www.qdfuns.com/notes/23720/d3990bb38177fd0c14789a7c54e614d9.html

深入理解js構造函數:http://www.cnblogs.com/wangyingblog/p/5583825.html

?

現在來創建一個構造函數用做房子和公寓對象的模板。

function Accommodation(){};

要想把這個函數用作模板來創建對象,需要用到new這個關鍵字。

var house= new?Accommodation();

var apartment = new?Accommodation();

用關鍵字new創建的所有對象都被稱為這個函數所示結構的對象實例,創建對象的過程就是這個模板實例化的過程。同一個模板的對象實例之間互無關聯,這些對象實例是完全獨立的變量,只不過共享同一個模板結構而已。

1.找出函數的構造器

通過上面的方法用模板創建的對象還有一個額外的屬性,叫做constructor,這個屬性指向創建該對象時使用的JavaScript構造函數。我們可以直接將對象的constructor屬性和某個構造函數進行比較。

house.constructor ===?Accommodation;//true

apartment.constructor ===?Accommodation;//true

這種比較也可以使用關鍵字 instanceof 來完成,該關鍵字的作用就是檢查對象是否是某個構造函數的實例。
house instanceof ?Accommodation;//true

apartment?instanceof ?Accommodation;//true

2.通過原型添加屬性和方法

JavaScript中的每個函數,即每個構造器,都有一個叫prototype的屬性。

(1)使用prototype關鍵字和點標記法為構造器添加屬性和方法

//定義一個名為Accommodation的構造函數

function Accommodation(){}

//為這個“類”添加屬性

Accommodation.prototype.floors=0;

Accommodation.prototype.rooms=0;

//為這個“類”添加方法

Accommodation.prototype.unlock=function(){};

創建“類”的對象實例

var house= new?Accommodation();

var apartment = new?Accommodation();

?

(2)通過對象直接量為構造函數添加屬性和方法

1 //定義一個名為Accommodation的構造函數 2 3 function Accommodation(){} 4 5 Accommodation.prototype={ 6 7   floors:0, 8 9   lock:function(){} 10 11 };

?

prototype這個關鍵字有一個強大的特性是允許在對象實例已經創建之后繼續添加屬性和方法,而這些新添屬性和方法會自動添加到所有對象實例中,不管是已經創建的還是將要創建的————

1 function Accommodation(){} 2 3 Accommodation.prototype={ 4 5   floors:0, 6 7   lock:function(){} 8 9 }; 10 11 var house = new Accommodation(); 12 13 house.prototype.unlock=function(){}; 14 15 house.unlock();

?

?

3.通過作用域添加屬性和方法

函數體內定義的任何變量或函數,其作用域都限于函數體內,就是說在該函數體以外無法訪問這些變量或函數 -- 對這些變量和函數來說,包裹它們的外層函數提供了一個沙箱般的編程環境,或者說一個閉包。

(1)變量作用域

//定義在任何函數之外的變量在全局作用域內,可以再任何位置訪問

1 //定義在任何函數之外的變量在全局作用域內,可以再任何位置訪問 2 var myLibrary={ 3 myName:"Dennis" 4 }; 5 function doSomething(){ 6 //函數體內定義的變量無法在函數體外訪問到 7 var innerVariable=123; 8 myLibrary.myName="Hello"; 9 function doSomethingElse(){ 10 innerVariable=1234; 11 } 12 doSomethingElse(); 13 alert(innerVariable); 14 } 15 doSomething(); 16 //該屬性在doSomething函數中已被覆蓋 17 alert(myLibrary.myName); 18 19 //在一個函數之外訪問其內部定義的變量將導致錯誤 20 alert(innerVariable);//Error

?

?

4.上下文和this關鍵字

JavaScript中this關鍵字代表的是一個函數的上下文環境,這個上下文環境在大多數情況下指的是函數運行時封裝這個函數的那個對象。當不通過任何對象單獨調用一個函數時,上下文環境指的就是全局的window對象。

在一個對象的方法中使用this指向的是這個對象本身,比如下面例子中的house對象。使用this關鍵字而不是對象的變量名,這么做的好處在于你可以隨意改變對象的變量名而不用擔心對象中方法的行為受到影響。

this關鍵字成為了其指向的對象的代名詞,所以和對象一樣,你可以對這個關鍵字本身使用點標記法。

(1)使用this關鍵字和點標記法

1 //在所有函數之外,this表示的是全局的window對象 2 alert(this===window);//true 3 //因為doSomething函數在對象外部被調用,this指向的是瀏覽器的window對象 4 function doSomething(){ 5 alert(this===window);//true 6 } 7 doSomething(); 8 var house={ 9 floors:2, 10 isLocked:false, 11 lock:function(){ 12 alert(this===house);//true,因為this關鍵字表示的是包含這個方法的那個對象 13 14 //我們可以把this看作house對象的替身,可以使用點標記法 15 this.isLocked=true; 16 } 17 }; 18 house.lock(); 19 alert(house.isLocked);//true

對象中的嵌套函數其上下文環境是全局的window對象,而非包含它的那個對象,這一點可能出乎你的預料,很多人都會在這里出錯。要想繞過這個陷阱,我們可以再this指向包含這個函數的對象時,將this的值保存在一個變量中,然后在用到該對象時,用這個變量來代替。很多開發者都用一個名為that的變量來保存這個對象引用-----

(2)將this關鍵字的值保存在變量中

1 var apartment={ 2 isLocked:false, 3 lock:function(){ 4 var that=this; 5 //設置isLocked屬性 6 this.isLocked=true; 7 function doSomething(){ 8 alert(this===apartment);//false 9 alert(this===window);//true 10 alert(that===apartment);//true 11 //通過that變量來修改apartment對象的isLocked屬性 12 that.isLocked=false; 13 } 14 doSomething(); 15 } 16 }; 17 apartment.lock(); 18 alert(apartment.isLocked);//false

在使用new關鍵字創建對象時,this指向的值和一般情況下又有區別。在這種情況下,this指向的是通過構造函數所創建的那個對象實例。正是因為這個特性,我們得以構造函數中通過this來設置所有對象實例的屬性和方法,而非像之前那樣使用prototype關鍵字--

(3)在構造函數中使用this關鍵字

1 //定義一個新的構造函數來表示一種豪宅 2 function Accommodation(){ 3 //this關鍵字指向的是通過這個“類”創建的對象實例 4 this.floors=0; 5 this.rooms=0; 6 this.sharedEntrance=false; 7 this.isLocked=false; 8 this.lock=function(){ 9 //函數中的this一般指向包含函數的那個對象,本例中this指向的是創建對象實例, 10 //因為這個函數時通過這個被創建的對象實例來調用的 11 this.isLocked=true; 12 } 13 this.unlock=function(){ 14 this.isLocked=false 15 }; 16 } 17 //通過構造函數來創建對象實例 18 var house =new Accommodation(); 19 var apartment =new Accommodation(); 20 21 //讀取和修改屬性值,調用方法等操作都和普通對象一樣 22 alert(house.floors);//0 23 house.floors=2; 24 apartment.lock();

JavaScript開發者一般會結合使用prototype和this關鍵字來定義對象實例的屬性和方法,其中前者用來定義方法,后者用來定義屬性。每次通過構造器創建一個新的對象實例,構造函數都會被執行一次。

之所以組合使用這兩個關鍵字,是為了避免每次初始化一個對象實例時都要執行那些對方法進行初始化的代碼。通過prototype關鍵字來定義的方法只需定義一次,然后就可以為所有通過這個構造函數創建的對象所用,這個使得對象的創建變得更加高效。在原型上定義的方法可以通過this來得到對象實例的引用---

(4)組合使用this和prototype關鍵字編寫高效的構造函數

1 //通過一個構造函數來表示各種類型的住宅 2 function Accommodation(){ 3 //利用this關鍵字來設置實例對象的屬性 4 this.floors=0; 5 this.isLocked=false; 6 } 7 //利用prototype關鍵字來定義實例對象的方法 8 Accommodation.prototype.lock=function(){ 9 //通過原型定義的方法可以通過this關鍵字訪問在構造函數中定義的屬性 10 this.isLocked=true; 11 } 12 Accommodation.prototype.unlock=function(){ 13 //通過原型定義的方法可以通過this關鍵字訪問在構造函數中定義的屬性 14 this.isLocked=false; 15 } 16 //實例化一個Accommodation類型的對象 17 var house =new Accommodation(); 18 //執行“lock”方法 19 house.lock(); 20 //檢查“isLocked”屬性是否正確設置 21 alert(house.isLocked);//true 22

開發者們喜歡在構造函數中使用this關鍵字來設置屬性的另一個原因是可以給構造函數傳遞參數,這樣我們就能再構造函數時通過傳遞參數來對某些屬性進行初始化了。我個人喜歡用this關鍵字來初始化那些我希望在對象創建時進行初始化的屬性,

而用prototype設置其他屬性以及對象的方法。這樣一來,構造函數就不需要出現任何在對象初始化時不需要被執行的代碼了,代碼變得更高效。

(5)在構造函數中通過this關鍵字初始化屬性

1 //定義一個帶有三個參數的構造函數,這些參數的值用于初始化實例對象的屬性 2 function Accommodation(floors,rooms,sharedEntrance){ 3 //當該“類”的一個對象被實例化時,用傳進來的參數值初始化該對象的三個屬性 4 //邏輯或操作的作用是在傳入值為空時指定一個默認值 5 this.floors=floors||0; 6 this.rooms=rooms||0; 7 this.sharedEntrance=sharedEntrance||false; 8 } 9 //不需要在實例化時賦值的屬性應該通過prototype來進行設置,因為這樣就只需定義和執行一次 10 Accommodation.prototype.isLocked=false; 11 12 Accommodation.prototype.lock=function(){ 13 this.isLocked=true; 14 } 15 16 Accommodation.prototype.unlock =function(){ 17 this.isLocked=false; 18 } 19 20 //實例化“類” 的一個對象,傳遞三個參數中的兩個值用于初始化 21 //參數值是按照構造函數的參數定義順序進行傳遞的 22 var house =new Accommodation(2,7); 23 alert(house.floors); 24 alert(house.rooms); 25 26 //參數sharedEntrance的值沒有被傳入構造函數,所以它的值通過邏輯或操作被設置為默認值false 27 alert(house.sharedEntrance);

?

當你的“類”規模越來越大時,你會發現為了給對象實例的屬性設置初始值,需要給構造函數傳遞一系列參數值。當參數個數不多時,依次列出每個參數的值是可行的,但是當參數個數超過三個或四個的時候,這么做就變得既困難又容易出錯。幸運的是,對象直接量為我們提供了一種解決方案。我們可以向構造函數傳遞一個對象直接量作為唯一參數,這個對象直接量包含了進行屬性設置所需的所有初始值。

這樣一來我們不但消除了多個函數參數帶來的不便,同時也使代碼變得更加清晰易懂,因為對象直接量是以名對值對的形式出現的,這比沒有名字的函數參數值更直觀。當需要給一個函數傳遞兩個或者三個以上參數值時,我會選擇這種方式

(6)用對象直接量作為構造函數的參數

1 function Accommodation(defaults) { 2 //如果沒有傳入值,默認為空的對象直接量 3 defaults = defaults || {}; 4 //如果default對象含有某個屬性,就將實例對象中同名屬性的值設為default提供的值,否則設為默認值 5 this.floors = defaults.floors || 0; 6 this.rooms = defaults.rooms || 0; 7 this.sharedEntrance = defaults.sharedEntrance || false; 8 } 9 10 Accommodation.prototype.isLocked = false; 11 12 Accommodation.prototype.lock = function() { 13 this.isLocked = true; 14 } 15 Accommodation.prototype.unlock = function() { 16 this.isLocked = false; 17 } 18 //實例化兩個Accommodtion“類”的對象,通過對象直接量傳遞命名的參數 19 var house =new Accommodation({ 20 floors:2, 21 rooms:7 22 }); 23 var apartment=new Accommodation({ 24 floors:1, 25 rooms:4, 26 sharedEntrance:true 27 });

?

5.方法的鏈式調用

我們已經在對象實例上定義過方法了,這些方法的調用方式和普通函數并無不同,只需在方法名后面加上一對括號即可。要想連續調用對象實例的多個方法,我們現在必須依次逐個調用,每個調用獨占一行,而且每次調用都必須寫出對象名。

house.lock();

house.alarm();

house.unlock();

只要對每個方法做一個小改變,我們就能對其進行鏈式調用了,就是說一個方法調用可以緊跟在另外一個后面。如果你用過jquery,你或許見過類似的語法。

house.lock().alarm().unlock();

要實現鏈式調用,只需在“類”中的每個方法最后通過this關鍵字返回對象實例的引用即可。

?

?(1)通過this關鍵字來實現方法的鏈式調用

1 function Accommodation() {} 2 3 Accommodation.prototype.isLocked = false; 4 Accommodation.prototype.lock = function() { 5 this.isLocked = true; 6 7 //通過返回上下文,我們實際上返回了調用這個函數的那個對象實例。因為這個對象包含了所有的方法, 8 //所以我們可以在本方法調用結束后馬上調用其他方法 9 return this; 10 } 11 12 Accommodation.prototype.unlock=function(){ 13 this.isLocked=false; 14 return this; 15 } 16 17 Accommodation.prototype.alarm = function(){ 18 alert("Sounding alarm"); 19 return this; 20 } 21 //創建一個新實例 22 var house =new Accommodation(); 23 24 //因為每個方法都返回其執行上下文,(在本例中即包含這些方法的對象實例) 25 //我們得以將這些方法調用一個接一個地鏈接在一起 26 house.lock().alarm().unlock();

?

?6.繼承

傳統編程語言的一項關鍵功能就是可以創建一些新的類,來繼承或者擴展某個父類的屬性和方法,這些新的類和該父類都有某種類似的邏輯關聯。這些新的類被稱為子類。JavaScript中也可以實現這種繼承,不過實現方式和傳統語言不盡相同。在JavaScript中被稱為原型繼承,通過JavaScript對象的原型鏈來實現。

(1)通過原型繼承創建一個子類

?

1 //定義一個有兩個方法的“類” 2 function Accommodation() {} 3 Accommodation.prototype.lock = function() {}; 4 Accommodation.prototype.unlock = function() {}; 5 6 //定義一個構造函數,它將成為我們的子類 7 function House(defaults) { 8 defaults = defaults || {}; 9 //將本“類”所有實例的floors屬性初始化為“2” 10 this.floors = 2; 11 //如果構造函數的對象直接量參數包含“rooms”屬性,則使用傳進來的值,否則默認設為7個房間 12 this.rooms = defaults.rooms || 7; 13 } 14 15 //將House“類”的原型設為Accommodation“類”的一個實例 16 //使用關鍵字new來調用Accommodation的構造函數,這樣就能創建并返回一個包含其所有屬性和方法的對象 17 //這個對象被傳遞給House“類”的原型,這樣House“類”就得以繼承Accommodation的所有內容 18 House.prototype = new Accommodation(); 19 20 //對象實例的constructor屬性指向創建該對象的那個構造函數。然而,由于House繼承了Accommodation的所有內容, 21 //constructor的值也被復制了,所以我們現在需要重設constructor的值,使其指向新的子類,如果沒有這一步, 22 //通過House 類 創建的對象就會報告說它們是通過 Accommodation 類 創建的 23 24 House.prototype.constructor = House; 25 //創建House的一個實例,繼承Accommodation的屬性和方法 26 var myHouse = new House(); 27 28 //傳入rooms的值從而在對象實例化時對rooms進行賦值 29 var myNeighborsHouse = new House({ 30 rooms: 8 31 }); 32 alert(myHouse.rooms); //7(House構造函數中的默認值) 33 alert(myNeighborsHouse.rooms); //8 34 35 //Accommodation的方法對House的對象也可用 36 myHouse.lock(); 37 myNeighborsHouse.unlock(); 38 39 //由于之前我們修改了constructor的值,所以由House創建的對象能如實報告這一點 40 alert(myHouse.constructor === House); //true 41 alert(myHouse.constructor === Accommodation); //true 42 43 44 //instanceof關鍵字會沿原型鏈進行查詢,所以也可用于檢查一個對象實例是不是在某個父類 45 46 // alert(myNeighborsHouse instances House); 47 // alert(myNeighborsHouse instances Accommodation);

?

我們之前曾使用prototype關鍵字來傳給構造函數添加過方法和屬性,所有通過這個構造函數創建的對象都能訪問到這些方法和屬性。
如果我們試圖訪問對象的某個方法或屬性,但構造函數的原型并沒有這個方法或屬性,此時JavaScript并不會馬上拋出異常,而是會首先檢查當前構造函數的所有父構造函數,
看這些父構造函數是否包含該方法或屬性。

*注意:當創建一個子類時,要確保將子類的constructor屬性指向子類本身的構造函數,因為從原型中直接復制過來的constructor值默認指向的是父類的構造函數。

我們看到instanceof關鍵字會沿原型鏈進行查詢,這意味著通過instanceof關鍵字可以判斷一個對象實例是不是由某個構造器,或者該構造器的某一個父構造器創建的。
JavaScript中的原型鏈可以一直向上追溯到內建的Object的類型,因為JavaScript的所有變量最終都是繼承自該類型。

alert(myHouse instanceof House);//true
alert(myHouse instanceof Accommodation);//true 因為House繼承自Accommodation
alert(myHouse instanceof Object);//true,因為所有對象都繼承自JavaScript的內置對象Object

?

●封裝

當通過繼承對已有的類進行改變或特殊化時,父“類”的所有屬性和方法對子類都是可用的。在子類中不需要額外生命或者定義任何東西就能夠使用父類的屬性和方法。這種特性被稱為封裝;子類只需要定義那些在父類基礎上新增的屬性和方法即可。

●多態

在構造一個新的子類來繼承并擴展一個“類”的時候,你可能需要將某個方法替換為一個同名的新方法,新方法和原方法功能類似,但對子類做了針對性的改變。這就是多態,在JavaScript中實現多態很簡單,只需重寫一個函數并給它一個和原方法相同的方法名即可。

(2)多態

?

1 // 定義父"類" Accommodation 2 function Accommodation(){ 3 this.isLocked=false; 4 this.isAlarmed=false; 5 } 6 // 為所有的Accommodation添加方法,執行一些常見動作 7 Accommodation.prototype.lock=function(){ 8 this.isLocked=true; 9 } 10 Accommodation.prototype.unlock=function(){ 11 this.isLocked=false; 12 } 13 Accommodation.prototype.alarm=function(){ 14 this.isAlarmed=true; 15 alert("Alarm activated"); 16 } 17 Accommodation.prototype.deactivateAlarm=function(){ 18 this.isAlarmed=false; 19 alert("Alarm deactivated"); 20 } 21 //為House定義一個子類 22 function House(){} 23 24 //繼承自Accommodation 25 House.prototype=new Accommodation(); 26 //針對House"類"重定義lock方法,即多態 27 28 House.prototype.lock=function(){ 29 //執行父類Accommodation的lock方法。可以通過“類”的原型直接訪問這個方法。我們通過函數的call 30 //方法對上下文傳遞給該方法,從而確保在lock方法中任何對this的引用都指向當前這個House的對象實例 31 Accommodation.prototype.lock.call(this); 32 alert(this.isLocked);//true 說明上面對lock方法的調用是正確的 33 //調用繼承自Accommodation的alarm方法 34 // this.alarm(); 35 } 36 //以同樣的方式重定義unlock方法 37 House.prototype.unlock=function(){ 38 Accommodation.prototype.unlock.call(this); 39 this.deactivateAlarm(); 40 }

注意觀察我們是如何在重寫的新方法中訪問正在進行多態化的原方法的,我們只需要通過父“類”定義中的prototype屬性直接訪問這個方法就可以了。因為該方法中包含對其上下文的引用,即this,我們需要保證this指向的是通過子類創建的對象實例所代表的上下文。

我們通過調用call方法來實現這一點,該方法對JavaScript中所有函數都可用,其作用就是將一個函數的上下文應用到另外一個函數身上。

●JavaScript函數的apply和call方法

我們之前討論上下文的問題;JavaScript中的this關鍵字指向的是包含當前方法的那個對象,而在面向對象的JavaScript編程中,this指向的就是由某個“類”創建的一個對象實例。

當調用其他對象而非代表當前上下文的對象的方法時,該方法中所有對this的引用都指向此方法所在的對象,而非當前代碼的執行上下文——就是說在調用這個方法時,你切換到了另外一個上下文中。在調用其他對象的方法時,我們需要一種機制來保持this原來的值。

為實現這一點,JavaScript提供了相似的兩個方法——apply和call,這兩個方法可以用于所有函數。

前面討論多態時,我們看到call這個方法可以用于在子類中調用父類的方法。在那個例子中,我們將指向子類對象實例的上下文直接傳給了一個通過父類原型來調用的方法。這個一來該方法中所有的this就會指向那個子類的對象實例,通過這種方式,我們將一個位置的上下文應用到了另一個位置上。如果需要向函數傳遞函數,可以將這些函數在上下文后面列出。call和apply的區別在于,使用apply時,所有的參數都應放在一個單獨數組參數中,而在使用call的時候,參數應該一次列出把并用逗號隔開。

?(3)在一個函數上使用apply和call方法

1 // 定義一個簡單的"類" 2 function Accommodation(){ 3 this.isAlarmed=false; 4 } 5 //創建一個對象,其方法可以被代碼中的其他對象所使用一該對象也被稱為一個“mixin”(混入) 6 var AlarmSystem={ 7 arm:function(message){ 8 this.isAlarmed=true; 9 alert(message); 10 }, 11 disarm:function(message){ 12 this.isAlarmed=false; 13 alert(message); 14 } 15 }; 16 var myHouse =new Accommodation(); 17 //通過call,將對象實例上下文傳入arm函數 18 AlarmSystem.arm.call(myHouse,"Alarm activated"); 19 //arm函數中this的值指向通過call傳入的對象實例,所有myHouse對象的isAlarmed屬性被改變了 20 alert(myHouse.isAlarmed);//true 21 //通過apply也能達到同樣的效果,只不過參數是通過數組來進行傳遞的 22 AlarmSystem.disarm.apply(myHouse,["Alarm activated"]); 23 alert(myHouse.isAlarmed);//false

◆arguments

執行一個函數時,我們傳入函數的所有參數都成為可以在該函數中使用的變量。除此之外,JavaScript還有一個可以在函數中使用的保留關鍵字arguments,我們可以把arguments看作一個數組arguments,其中依次包含了傳入該函數的各個參數。

設想你有一個函數,你想用這個函數來對所有作為參數傳入的數字進行加和。如果你不想指定具體有幾個參數,可以將參數列表清空,轉而使用arguments這個偽數組來獲取參數,如代碼(4)所示。之所以稱arguments為偽數組時因為雖然可以通過for循環對其進行遍歷,但它不具備標準數組的方法,例如排序方法,所有在使用arguments的時候不應該用到這些數組方法。

(4)arguments對象

1 // 創建一個函數,對傳入函數的所有參數進行加和 2 var add=function(){ 3 //創建一個變量用來保存總和 4 var total=0; 5 //arguments這個偽數組包含所有傳入該函數的參數,遍歷每個參數并將加入總和中 6 7 for(var index=0,length=arguments.length;index<length;index++){ 8 total=total+ arguments[index]; 9 } 10 return total; 11 } 12 //用不同數量的參數對函數進行測試 13 alert(add(1,1));//2 14 alert(add(1,2,3));//6 15 alert(add(12,123,3,1234));//1372

當使用函數的apply方法時,arguments偽數組就體現其價值了。因為apply方法將所有參數放入了一個數組內進行傳遞,當被調用的函數與當前函數擁有相同參數時,我們只需要傳入arguments,就把當前函數的所有參數傳遞給了另一個函數。這對對象的繼承和多態很有用,因為我們可以通過arguments,將子類方法的所有參數直接傳遞給父類中的相似方法。

(5)在子類中使用arguments偽數組

1 // 定義父類Accommodation 2 function Accommodation(){ 3 this.isAlarmed=false; 4 } 5 Accommodation.prototype.alarm=function(note,time){ 6 var message="Alarm activted"+time+"with the note:"+note; 7 this.isAlarmed=true; 8 alert(message); 9 } 10 //定義子類House 11 function House(){ 12 this.isLocked=false; 13 } 14 //繼承Accommodation 15 House.prototype=new Accommodation(); 16 //為House子類重定義alarm方法,方法定義中沒有列出參數,因為我們會把所有參數直接傳遞給父類中的同名方法 17 House.prototype.alarm=function(){ 18 this.isLocked=true; 19 //調用父類Accommodation的alarm方法,將當前函數的所有參數直接傳遞給父類方法以無需將這些參數一一列出 20 Accommodation.prototype.alarm.apply(this,arguments); 21 } 22 //創建子類的一個對象實例并進行測試 23 var myHouse=new House(); 24 myHouse.alarm("Activating",new Date());//彈出警告消息 25 26 alert(myHouse.isLocked);//true

?●公有,私有,以及受保護的屬性和方法

在之前的例子中,我們創建了很多“類”模板,這些類模板將屬性和方法綁定到構造函數的prototype屬性上,或者通過this關鍵字,將其綁定到這些“類”創建的對象實例所代表的上下文中。通過這種方法創建的屬性和方法都是公有的,也就是說這些屬性和方法對一個“類”的所有對象實例都可用,從而代碼中所有能夠訪問這些對象實例的地方都能使用這些屬性和方法。

然而在某些情況下,你可能希望能夠限制某些屬性和方法的暴露程度,使它們不能直接通過對象實例本身被隨意訪問,修改或調用。許多傳統的編程語言可以將屬性和方法定義為公有,私有,或者受保護的,以此來限制對這些屬性和方法的訪問。私有變量或方法在類定義之外不能進行讀寫;受保護的變量不能被直接訪問,但可以通過一個包裝方法對其讀寫。這些包裝方法通常被稱為getter和setter,你可以通過這些方法讀取或者設置對象實例的屬性值。如果你只定義了一個getter函數,那么變量在類定義之外就變為了只讀的了。在JavaScript中并沒有具體的語法來定義私有或者受保護的變量或方法,不過我們可以對聲明“類”的方法做一些改變,從而限制對屬性和變量的訪問。

在構造函數中通過var定義的變量其作用域局限于該構造函數內——在prototype上定義的方法無法訪問這個變量,因為這些方法有其自己的作用域。要想通過公有的方法來訪問私有的變量,需要創建一個同時包含兩個作用域的心作用域。為此,我們可以創建一個自我執行的函數,被稱為閉包。該函數完全包含了“類”的定義時,包括所有私有變量以及原型方法,如代碼(6)

JavaScript有一個非強制性的但很有用的編程慣例,就是對所有私有變量或函數名加一個下劃線(_)作為前綴,以標識它們是私有的。這有助于你以及項目組的其他開發人員更好地理解每個“類”的作者的意圖。

(6)公有、私有以及受保護的屬性和方法

?

1 //我們將“類”的定義包在一個自我執行的函數里,這個函數返回我們所創建的“類”并將其保存在一個變量中以便在后面的代碼中使用 2 3 var Accommodation =(function(){ 4 //定義"類"的構造函數,因為處在一個新的函數內,我們也切換到了一個新的作用域中,所以可以使用與保存函數返回值得那個變量相同的名字 5 function Accommodation(){} 6 //此處定義所有變量都是“私有的”,這些變量在當前作用域之外不可用,可以通過給變量名添加下劃線前綴來標識這一點 7 var _isLocked=false, 8 _isAlarmed=false, 9 _alarmMessage="Alarm activated"; 10 11 //僅在當前作用域中定義的函數(而未在構造函數的原型上定義)也都是“私有的” 12 function _alarm(){ 13 _isAlarmed=true; 14 alert(_alarmMessage); 15 } 16 function _disableAlarm(){ 17 _isAlarmed=false; 18 } 19 //所有定義在原型上的方法都是“公有的”,當我們在此處創建的“類”在閉包結束處被返回后,就可以再當前作用域之外訪問這些方法了 20 Accommodation.prototype.lock=function(){ 21 _isLocked=true; 22 _alarm(); 23 24 } 25 Accommodation.prototype.unlock=function(){ 26 _isLocked=false; 27 _disableAlarm(); 28 } 29 //定義一個getter函數來對私有變量_isLocked的值進行只讀訪問————相當于把變量定義為了“受保護的” 30 Accommodation.prototype.getIsLocked=function(){ 31 return _isLocked; 32 } 33 //定義一個setter函數來對私有變量_alarmMessage進行只寫訪問——相當于定義為了“受保護的” 34 Accommodation.prototype.setAlarmMessage=function(message){ 35 _alarmMessage=message; 36 } 37 //返回在這個作用域中創建的“類”,使之在外層作用域中即后面代碼的所有位置都可用。只有公有的屬性和方法是可用的 38 39 return Accommodation; 40 }()); 41 42 43 //創建一個對象實例 44 var house =new Accommodation(); 45 house.lock();//彈出警告消息 “Alarm activated” 46 // house._alarm();//錯誤! _alarm函數從未被公開暴露,所以無法直接通過“類”的對象實例進行訪問 47 48 alert(house._isLocked);//undefined (_isLocked是私有的,在閉包外都訪問不到) 49 50 house.getIsLocked();//true (返回__isLocked的值,但是不允許對其進行直接訪問,所以該變量是只讀的) 51 52 house.setAlarmMessage("Hello world"); 53 house.lock();//彈出警告消息 “Hello world”

?一般情況下,我們應該將所有變量和函數都定義為私有的,除非明確需要將某些變量或方法公開暴露給外部。即使需要公開暴露,也應先考慮使用getter以及setter方法來訪問變量,
這么做的好處是可以顯示他人對稱的“類”所能實施的操作,使其只能通過“類”提供的功能完成其需求,這樣有助于減少“類”的使用者代碼出錯的機會。

●簡化繼承

我們可以通過定義一個基類來簡化對象的創建和繼承,其他所有類的創建都可以通過這個基類來完成。我們在這個基類上定義一個方法使之可以通過該方法來繼承其自身,并允許子類通過一個屬性來訪問父類,這么做可以讓子類的創建和使用變得簡單很多。我們還可以將那些用來在原型上設置方法的代碼包裝在一個單獨的對象直接量里,甚至將構造函數也包含在該直接量中,這樣一來“類”的創建就變得輕而易舉了。如代碼1-19
代碼清單1-19  一個用于簡化其他“類”創建的基“類”

?

代碼清單1-20  “類”創建器的實際使用

?

?

1.2?代碼規范和命名

前面詳細介紹了如何在JavaScript中進行面向對象編程,現在來看一下我們遵循什么樣的代碼規范,以及如何對變量和函數的命名,以便讓名字本身傳達含義,并確保大型團隊里的所有成員都能保持相似的編程風格。
在JavaScript中,我們通過關鍵字var加變量名以及一個可選的變量初值來定義變量,這樣就可以將變量保存在內存中以便在代碼中對其復用。同樣的函數也可以被保存在內存中并重復執行,我們通過關鍵字function加函數名來定義函數。
你可以隨便對變量和函數進行命名,前提是這些名字遵守下面規則.

名字的開頭必須時下面這些字符之一
?□ a-z、A-Z中的一個字母
?□ 下劃線_
?□ $符號
第一個字符之后,除了以上字符之外還可以使用0-9的數字
以下例子都是合法的JavaScript變量名和函數名

1 var a; 2 3 function A() {}; 4 var a1; 5 6 function _() {}; 7 var _a; 8 9 function $() {}; 10 var $_$;

這些是都是語言本身的固定規則,但是作為開發人員為了便于開發和維護,我們希望代碼是易讀易懂的,所以除了這些固定的規則之外,我們會規定一些額外的命名規范,這些規范被很多開發人員和編程語言所采納。要切實遵循這些命名規范,你就能更容易清楚自己的代碼中每個變量時干什么的,當然也更好的理解別人的代碼。

1.2.1?規則1:使用描述性的名字

這條規則是最為重要的,所以我把它放在了第一位。變量名代表了變量中所保存的數據,所以我們需要給變量起一個最能確切描述其用途的名字,使代碼更易讀易懂。如下所示:

var greeting = "Hello world";

1.2.2 規則2:以小寫字母開頭

變量名開頭使用小寫字母,然后在后面的部分也盡可能多地使用小寫字母。這么做時為了避免與JavaScript的內建類型和對象發生混淆,這些內建類型和對象都以大寫字母開頭,例如String,Object,Math.

var age = 35;

不過在我的代碼中這條規則有幾個體例。首先是使用jQuery的時候,我會將查找到的DOM元素保存在變量中以免對其進行重復加載。在這種情況下,我會在這些變量名前面加一個$符號作為前綴,以便將這些表示DOM結點的變量和代碼中的其他變量加以區別。$前綴后面的部分則遵循和其他變量一樣的規則。例如:

var $body = $(document.body);

第二個特征時如何對那些作為構造器來使用的函數進行命名。稍后會對構造器進行更詳細的考察,簡單說JavaScript中的內建類型都是構造器,例如String,Number,Boolean等。所有用new關鍵字來調用函數都是構造器。這些構造器名字的首字母都應該是大寫,例如:

function MyTime() {};

var myTime = new MyTime();

第三個特例,我們在之前章節也提到了,就是構造函數內的私有變量和函數應該在名字前加一個下劃線(_)作為前綴,以區別于那些公有的變量和方法

?

1.2.3?規則3:使用駱駝命名(又稱駝峰命名法)來分割單詞

規則1要求我們使用描述性名字,但如果我們只使用小寫字母的話,當名字包含多個單詞時就會難以閱讀,例如:

var myemailaddress = "123@qq.com";

駝峰命名:
var myEmailAddress = "123@qq.com";

?

1.2.4 規則4:全局常量使用全大寫的名字

這條規則關心的是那些經常在計算中用到的所謂的幻數(magic number),例如在計算日期和時間時經常用到的一些零散數組,或者在一些計算中用到的真是世界中的常數值例如Pi,不少開發人員習慣在用到這些數字的時候直接使用它們,這雖然可行但是會導致混亂。下面例子演示了這一點。

var today = new Date();
todayInDays = today * 1000 * 60 * 60 * 24;

乍看上去,這段代碼只是一系列數字而已,這些數字時干什么的并不清楚。通過定義變量來對這些數字進行命名之后,讀懂這段代碼就容易多了。我們用全大寫的字符來標明這些變量的類型是固定數值,也就是常量————雖然常量在其他很多編程語言中是一個特性,但JavaScript并不具備這一點。常量名字中的單詞通過下劃線(_)來進行分割。如代碼所示:

1 var today = new Date(), 2 MILLISECS_IN_1_SEC = 1000, 3 SECS_IN_1_MIN = 60, 4 MINS_IN_1HOUR = 60; 5 todayInDays = today * MILLISECS_IN_1_SEC * SECS_IN_1_MIN * MINS_IN_1HOUR;

?

這樣的確增加了代碼量,但我認為為了讓代碼具備更好的可讀性這是值得的。這些常量可以在代碼中反復重用,代碼中的各種計算也因此變得更容易理解。

1.2.5?規則5:集中在一個語句中聲明函數體的所有變量并將其置于函數體頂部

JavaScript中可以使用關鍵字var用簡寫的方式在一個語句中同時定義多個變量,具體方式是用逗號隔開每個變量聲明。確保在使用變量之前對其進行聲明時明智的,這樣做可以避免執行代碼時出錯。因此我建議你將用到的所有變量在函數體頂部和JavaScript文件頂部進行聲明,并將這些生命合并到一個語句中。注意你不需要立即對這些變量進行初始化,初始化可以稍后進行,這里需要做的是一次性地提前所有變量進行聲明。用逗號和換行符分割各個變量,然后為了保證可讀性,我們將變量名首字母對其,如下所示:

1 var myString = "hi", 2 allStrongTags = "/<strong>(.*?)</strong>/g", 3 tagContents = "&1", 4 outputString; 5 outputString = myString.replace(allStrongTags, tagContents);

?

變量和函數名提升(Hoisting)
在其他很多編程語言中,變量可以在任意一個代碼塊中進行定義,例如一個for循環或者任何一個通常用一對花括號來標識的代碼塊,然后該變量的作用域就限定在那個代碼塊中了。而在
JavaScript中,我們知道作用域被限定為只在函數級起作用,這就使一些習慣于用其他語言進行開發的開發人員可能在這個問題上出錯,如代碼所示:

代碼清單1-21 代碼塊和作用域

1 function myFunction() { 2 var myArray = ["January", "February", "Maich", "April", "May"]; 3 myArrayLength = myArray.length; 4 counter = 0; 5 for(var index = 0; index < myArrayLength; index++) { 6 //每循環一次counter的值加1 7 counter = index + 1; 8 } 9 //這些變量的值應該是符合期望的 10 alert(counter); // 5 11 alert(index); //5(因為在判定循環條件之前循環遞進了一步) 12 alert(myArrayLength); //5 13 if(myArrayLength > 0) { 14 //在很多語言中,在這樣一個代碼塊中定義的變量其作用域也局限于該代碼中 15 //但JavaScript不是這樣的,所以在代碼塊中定義變量時要注意這一點 16 var counter, 17 index = 0, 18 myArrayLength, 19 counter = 0; 20 } 21 //即使代碼塊中使用了var來進行定義,counter和index的值還是在if語句中被改變了 22 alert(counter); //0 23 alert(index); //0 24 //注意雖然在代碼塊中用var對myArrayLength進行了重定義,但其值并未發生改變 25 //這是因為JavaScript在函數執行之前就將變量名“提升”到了函數頂部 26 alert(myArrayLength); //5 27 28 } 29 myFunction();

JavaScript有一種特性叫作"提升",就是說變量和函數聲明會在內部被提升到其定義所在函數體的頂部。這意味著任何一個變量名的定義都在其所在的作用域(通常是一個函數)的頂部就可以了,
雖然并不一定是初始值。為了減少麻煩,最好在函數開頭就列出函數中所要用到的所有變量,不管是否進行初始化,因為這么做是對JavaScript內部進行的變量提升行為是最好的模仿,能夠減少由于使用未知變量定義和變量值所引起的困惑,如代碼所示:
?在函數開頭處對函數中用到的所有變量進行定義

?

代碼清單1-22 ? ?在函數開頭處對函數中用到的所有變量進行定義

2 function myFunction(){ 3 //為了防止變量提升引起的錯誤,我們在函數頂部對其所有變量進行定義 4 5 var myArray=['January','February','March','April','May']; 6 myArrayLength=myArray.length, 7 counter=0, 8 index=0; 9 //for循環的第一部分通常是用來定義循環變量的,現在由于我們將定義都放在函數體頂部了,所以可以省略這一部分 10 11 for(;index<myArrayLength;index++){ 12 counter=index+1; 13 } 14 //變量的值應該不出所料 15 alert(counter);//5 16 alert(index);//5 17 alert(myArrayLength);//5 18 19 } 20 myFunction();

這一點對函數也同樣適用,函數名也會被提升,所以一個函數名在其當前作用域的任何位置都可用,即使在定義函數之前,如代碼所示:

代碼清單1-23 函數的提升

function myFunction(){//因為JavaScript的“提升”,在函數定義之前執行一個函數是可行的 doSomething();function doSomething(){alert("Doing something");}}myFunction();

1.3 ECMAScript 5
1.3.1 JSON數據格式解析

1 var obj = { 2 "success": false, 3 error_message: "error" 4 }; 5 JSON.parse(obj); //返回對象直接量 6 JSON.stringify(obj); //返回包含JSON格式的數據的字符串

1.3.2 嚴格模式

在包含該字符串的文件或函數中,所有代碼都必須符合更嚴格的語言規則,這些規則有助于避免潛在的錯誤和陷阱。在嚴格模式下,如果你使用了未定義的變量,JavaScript會報錯。

同樣,如果你使用了包含兩個同名屬性和對象的直接量(我自己也曾因這一點而吃虧),JavaScript也會發出警告;又比如detele關鍵字本應該用在對象的屬性上,如果你將其用在變量或函數身上,

JavaScript也會提示。嚴格模式還禁止使用eval來執行包含JavaScript代碼的字符串,因為這么做會引起安全問題,其他代碼可能會將控制權從你所寫的代碼中奪走。

?

因為執行嚴格模式只需要添加一個簡單的字符串,所以老的瀏覽器不會因此而出錯,當老瀏覽器執行你的代碼時遇到這個語句,它們會將其作為一個字符串來執行,因為這個字符串沒有被賦給任何變量,
所以實際上就被忽略了。比如代碼1-24的兩個函數,其中一個應用了普通模式,而另一個應用了嚴格模式。我已經開始在我所有的代碼中使用這個新的嚴格模式了,這么做是為了確保代碼質量足夠高,我也建議你來使用。

代碼清單1-24 演示ECMAScript5的嚴格模式

1 //定義一個函數 2 function myFunction(){ 3 //使用一個之前未定義的變量將隱式地將其創建為全局變量 4 counter=1; 5 //用eval()來執行包含JavaScript代碼的字符串不會報錯 6 eval("alert(counter)");// 7 //delete關鍵字的作用是移除對象的屬性和方法,但是將其用在變量身上不會報錯 8 delete counter; 9 } 10 myFunction(); 1 function myFunction(){ 2 "use strict" 3 //執行這一條語句時會報錯,因為counter變量未定義 4 counter=1; 5 //eval因為安全問題應該避免使用,所以這里會報錯 6 eval("alert(counter)");// 7 //delete關鍵字只應該被用于移除對象直接量的屬性和方法,所以這里會報錯 8 delete counter; 9 } 10 myFunction();

1.3.3  函數綁定

?我們之前介紹過可以用于JavaScript中所有函數的apply和call方法。ECMAScript5中增加了一個新的方法bind,這個方法不會直接執行函數,而是會返回一個新的函數。這個新函數的上下文設定為調用bind方法時,作為第一個參數傳入的任意對象.

你在自己的代碼中可能已經遇到

?

代碼清單1-15 函數的bind方法

1 var header=document.getElementById("header"); 2 eventHandlers={ 3 //定義一個包含三個方法的對象 4 onClick:function(){ 5 //如果onClick函數被調用時的執行上下文是錯誤的,以下兩個調用將失敗 6 this.onMouseDown(); 7 this.onMouseUp(); 8 }, 9 onMouseDown:function(){ 10 mouseState="down"; 11 }, 12 onMouseUp:function(){ 13 mouseState="up"; 14 } 15 }; 16 //強制eventHandlers.onClick使用正確的上下文,為此我們通過bind方法返回一個新的函數 17 //該函數就根據我們的要求綁定了相應的上下文 18 header.addEventListener("click",eventHandlers.onClick.bind(eventHandlers),false); 19 //將<header>元素添加到頁面 20 document.body.appendChild(header);

1.3.4 數組方法

大多數專業的javascript開發者每天都會用到數組,不管是用來進行循環,排序還是組織數據。ECMAScript5為javascript開發者的工具箱添加了一些大家期待已久的新方法,我么可以利用這寫新方法來處理這些數據結構

首先,也許也是最重要的,是我們需要一種方法,以便更容易地判斷一個變量是否包含數組數據。這也許聽起來有點奇怪,但別忘了要判斷一個變量是否包含數組數據,我們需要首先將其轉成對象,然后再把它的值讀取到一個字符串中————簡直是瘋 了!而在ECMAScript中,要檢查變量是否包含數組數據,我們只需要調用Array.isArray方法即可,如代碼1-26所示

代碼清單1-26  ECMAScript5中的isArray方法

1 var months=["January","February","March","April","May"], 2 items={ 3 "0":"January" 4 }; 5 alert(Array.isArray(months));//true 6 alert(Array.isArray(items));//false

在之前版本中,要遍歷一個數組,我們需要創建一個for循環,然后對某種類型的索引計數器進行迭代。EMAScript5引入了一個新的forEach方法,通過這個方法可以讓遍歷簡單很多;只需要給方法傳遞一個函數,它就會對數組中的每個元素調用一次該函數,同時會將當前遍歷的值、數組索引以及整個數組的引用傳遞給這個函數,如代碼清單1-27所示

代碼清單1-27 ECMAScript5的forEach方法

1 var months=["January","February","March","April","May"]; 2 //通過forEach方法我們可以遍歷數組中的每一個元素,同時每次執行一個函數 3 months.forEach(function(value,index,fullArray){ 4 alert(value+"is months number"+(index+1)+"of"+fullArray.length); 5 });

如果你曾有過這樣的需求,需要判斷數組中的每個元素是否滿足一個由某函數所定義的特定條件,那你可苦苦等待ECMAScript5中的新every方法太久了。與之類似的還有一個some方法,該方法會在數組中至少有一個元素滿足給定條件時返回true。every方法和some方法的參數都和forEach方法相同,如代碼清單1-28所示。

代碼清單1-28 ECMAScript5中的every和some方法

1 var months=["January","February","March","April","May"], 2 //every方法遍歷數組中的每個元素,將每個元素和一個條件進行比較 3 //如果數組中的每個元素都滿足這個條件,則every方法返回true,否則返回false 4 everyItemContaiinsR=months.every(function(value,index,fullArray){ 5 //根據當前遍歷到的元素是否滿足你指定的條件來返回true或者false,這里的條件就是看value是否包含字母r 6 return value.indexOf("r")>=0; 7 }), 8 //some 方法便利數組中的每個元素并將其和某個元素對比 9 //如果數組中的任意一個元素滿足該條件,則some方法返回true,否則返回false 10 someItemContainsR=months.some(function(value,index,fullArrary){ 11 return value.indexOf("r")>=0; 12 }); 13 14 //不是所有元素都包含字母r 15 alert(everyItemContaiinsR);//false 16 //但有些元素包含 17 alert(someItemContainsR);//true

新的map方法可以讓你根據一個已有的數組創建一個新的數組,它在創建新數組的過程中,每生成一個元素時都執行一個函數,如代碼清單1-29所示

代碼清單1-29 ECMAScript5中的map方法

1 var daysOfTheWeek=["Mondy","Tuesday","Wednesday"]; 2 //map方法通過遍歷一個已有的數組來生成一個全新的數組,它會在遍歷每個元素時執行一個函數, 3 //并通過該函數來生成新數組中的對應元素 4 daysFirstLetters=daysOfTheWeek.map(function(value,index,fullArray){ 5 return value="starts with"+value.charAt(0); 6 }); 7 alert(daysFirstLetters.join(","));//starts withM,starts withT,starts withW

ECMAScript5中新的filter數組方法和map一樣也會創建一個新的數組,不過新數組只包含滿足某個特定條件的那些元素,如代碼清單1-30所示

代碼清單1-30 ECMAScript5中的filter方法

1 var months=["January","February","March","April","May"], 2 //filer方法根據原有的數組創建一個削減版的數組,該數組只包含那些滿足某個特定條件的元素 3 monthsContainingR=months.filter(function(value,index,fullArray){ 4 //返回true或false來指示當前數組元素是否應該包含在過濾后的數組中,這里的判斷條件是看元素值是否包含字幕r 5 return value.indexOf("r")>=0; 6 }); 7 //唯一不包含字母r的月份是五月(May) 8 alert(monthsContainingR.join(","));//January,February,March,April

1.3.5 對象方法

ECMAScript5中對Object類型進行了很多擴展,這個javascript帶來了很多其他編程語言中的功能。首先,如果使用嚴格模式,ECMAScript5引入了一個新功能,就是可以將一個對象進行鎖定,這樣在你代碼中的某個點之后,就不能向該對象添加新的屬性或者方法了。實現這一功能的新方法是object.preventExtensions,以及一個與之相關的Object.isExtensible方法,通過該方法你可以判斷是否可以對一個對象進行擴展,如代碼清單1-31所示

代碼清單1-31 ECMAScript5中的對象方法

1 //定義一個包含兩個屬性的簡單對象 2 var personalDetails={ 3 name:"Den Odell", 4 email:"den.odell@me.com" 5 }; 6 alert(Object.isExtensible(personalDetails));//true ,因為默認對象都是可以擴展的 7 //阻止對personalDetails對象進行擴展 8 Object.preventExtensions(personalDetails); 9 10 alert(Object.isExtensible(personalDetails));//false ,因為該對象被鎖定了 11 12 //嘗試為personalDetails對象添加一個新的屬性 13 personalDetails.age=35;//如果使用嚴格模式的話會拋出錯誤,因為對象是鎖定的

如果你想進一步鎖定一個對象,使其已有的屬性值也無法改變,可以使用ECMAScript5中新的Object.freeze方法,如代碼清單1-32所示。

代碼清單1-32 ECMAScript5中對象的freeze方法

1 //定義一個有兩個屬性的簡單對象 2 var personalDetails={ 3 name:"Den Odell", 4 email:"den.odell@me.com" 5 }; 6 //鎖定該對象,使其已有的屬性也無法改變 7 Object.freeze(personalDetails); 8 alert(Object.isFrozen(personalDetails));//true 9 personalDetails.name="wing";//如果在嚴格模式下會報錯,因為對象一旦被"凍住"就無法再改變其屬性值

對象中的每個屬性現在都有一系列的選項值,它們決定這個屬性將如何在之后的代碼中被使用。這些選項值包含在一個屬性描述符中,該屬性描述符是一個有四個屬性的對象直接量。要想讀取某個屬性的屬性描述符,可以使用新的Object.getOwnPropertyDescriptor方法,如代碼清單1-33所示。描述符中的所有屬性,除了value屬性之外,默認值都是true

代碼清單1-33 ECMAScript5中對象的getOwnPropertyDescriptor方法

1 //定義包含兩個屬性的簡單對象 2 3 var personalDetails={ 4 name:"wing", 5 email:"den.odell@me.com" 6 }; 7 Object.getOwnPropertyDescriptor(personalDetails,"name"); 8 //返回代表name屬性的如下對象直接量 9 //{ 10 // configurable:true, 11 // enumerable:true, 12 // value:"wing", 13 // writable:true 14 //}

在ECMAScript5中你可以在創建屬性的同時定義其屬性描述值,如代碼清單1-34所示

代碼清單1-34 ECMAScript5中的屬性定義

1 var personalDetails={ 2 name:"wing", 3 email:"den.odell@me.com" 4 }; 5 //為該對象單獨定義一個新的屬性 6 Object.defineProperty(personalDetails,"age",{ 7 value:35, 8 writable:false, 9 enumerable:true, 10 configurable:true 11 }); 12 //同時定義多個屬性 13 Object.defineProperty(personalDetails,{ 14 age:{ 15 value:35, 16 writable:false, 17 enumerable:true, 18 configurable:true 19 }, 20 town:{ 21 value:"wing", 22 writable:true 23 } 24 })

如果你需要得到一個包含某個對象所有屬性名的數組,那么可以用Object.keys方法來實現,如代碼清單1-35

代碼清單1-35 ECMAScript5中對象的keys方法

1 var personalDetails={ 2 name:"wing", 3 email:"den.odell@me.com" 4 }, 5 keys=Object.keys(personalDetails); 6 alert(keys.join(","));//"name,email"

Object.create方法是一個功能強大的新方法,我們可以用該方法根據某個已有對象的屬性來創建一個新的對象。該方法一個可能的用處是創建某個已有對象的副本,如代碼清單1-36所示。

代碼清單1-36 ECMAScript5中對象的create方法

1 var personalDetails={ 2 firstName:"zhang", 3 lastName:"wei" 4 }, 5 //創建該對象的一個副本 6 fatherDetails=Object.create(personalDetails); 7 8 //定制這個副本對象 9 fatherDetails.firstName="chen"; 10 //通過原有對象所設置的屬性值未被更改 11 alert(fatherDetails.lastName);//"wei"

如果ECMAScript5中有一個值得你繼續深入研究的方法,那就是Object.create方法.

轉載于:https://www.cnblogs.com/wingzw/p/6681660.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的精通JavaScript--01面向对象JavaScript的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美污视频| 欧美一级二级视频 | 亚洲欧美第一页 | 久久理伦 | 包射屋| 神马三级我不卡 | 天天干中文字幕 | 亚洲熟悉妇女xxx妇女av | 青青草在线视频免费观看 | 午夜免费看 | 国产片在线 | 亚洲中文字幕视频一区 | 国产成人a亚洲精v品无码 | 国产男女猛烈无遮挡免费观看网站 | 一区二区传媒有限公司 | 视频二区在线 | 国产精品熟妇人妻g奶一区 a少妇 | 亚洲春色www | 麻豆69xxnxxporn | 国产aaaaaaa | 国产日韩欧美视频 | 国产精品二区视频 | 欧美精品一区三区 | 天天爽夜夜 | 蜜桃视频免费网站 | 色狠狠综合 | 日韩涩| 成人免费毛片嘿嘿连载视频 | 国产av日韩一区二区三区精品 | 特黄大片又粗又大又暴 | 天天曰夜夜操 | 国产精品爽爽爽 | av在线片| 极品尤物魔鬼身材啪啪仙踪林 | www.青青草 | 久久97精品 | 久久草国产 | 成人久久18免费网站图片 | 四虎在线观看 | 四虎影视免费在线观看 | 久久精品99国产国产精 | 一区二区三区国产精品视频 | 高柳家在线观看 | 上海贵妇尝试黑人洋吊 | 91精品国自产在线偷拍蜜桃 | www.日本高清 | 国产天堂第一区 | 都市激情 自拍偷拍 | 国产成人精品二区三区亚瑟 | 欧美亚洲免费 | 婷婷综合在线 | 一级视频在线播放 | 国精产品99永久一区一区 | 99国产免费 | 深夜福利网 | 中文精品在线 | 麻豆91茄子在线观看 | 91精品婷婷国产综合久久竹菊 | 在线观看国产黄 | 色片免费看 | 私拍在线 | 精品午夜一区二区 | 亚洲色图网址 | 欧洲精品二区 | 成人一区二区三区视频 | 欧美激情视频一区二区三区 | 久久久精品人妻一区二区三区色秀 | 蜜桃精品成人影片 | 亚洲精品久久久蜜桃网尤妮丝 | 亚洲人网 | 天天色天 | 欧美一区二区三区电影 | 色欧美视频 | 狠狠久| 亚洲免费大全 | 丰满人妻翻云覆雨呻吟视频 | 欧美乱妇一区二区三区 | 日韩精品专区 | 性盈盈影院中文字幕 | 九九在线免费视频 | 五月婷婷天| 成人国产一区二区三区精品麻豆 | 中文字幕免费观看 | 亚洲第一女人av | 国产又色又爽无遮挡免费 | 欧美浪妇xxxx高跟鞋交 | 亚洲精久久 | 4438x全国最大成人网 | 欧美天天影院 | 一级片一级 | 亚洲天堂中文字幕 | 亚洲毛片在线看 | 久久成人午夜 | 久久久.com | 中文在线观看av | 久久中文字幕在线观看 | 亚洲天堂视频在线播放 | 久久久久亚洲av成人片 | 国产精品美女av |