好程式設計師web前端培訓分享Javascript中原型屬性

好程式設計師IT發表於2019-04-01

本文將從以下三個方面講解原型屬性

  1 、 理解指標

  2 、 理解原型

  3 、 用原型的方式完成繼承

  以下為詳細內容:

  1 、 理解指標

  要理解 JAVASCRIPT 中的原型,先理解指標,在 C/C++ 中,會提到指標,其實,指標不應該屬於 C/C++ 的專利,上篇文章中,提到的引用型別 ( 也是很多物件導向語言中的資料型別的叫法 ) ,就是指標。

  C/C++ 中對指標的解釋:指標就是地址。地址為何物 ?

  地址:是計算機對記憶體每個儲存單元的管理方式。在計算機的記憶體中,儲存著若干資料,計算機的 CPU 是如何讀取記憶體中的資料的 ?

  計算機的每個儲存單元都有一個編號,就像到超市存包時,每個存包的格子都有一個編號,這個編號就是地址,記憶體的地址。超市每個格子為什麼要有編號,目的就是為了方便服務員進行查詢 ( 根據編號進行查詢 ) ,計算機每個儲存單元為什麼會有一個編號,目的也是為了 CPU 查詢記憶體。

01

  如果某個記憶體中直接儲存的是資料,則這種資料是基本型別的資料,如果某個記憶體中儲存的是其它記憶體的編號 ( 資料 ) ,那麼這種資料就叫引用型別的資料。

  2 、 理解原型

  a) 原型 ( 屬性 ) 的概念

  JAVASCRIPT 中的函式也是物件 ( 如果不懂函式也是個物件,請百度 JAVASCRIPT 中函式是功能完整的類 ) ,每個函式都有一個原型 (prototype) 屬性,這個屬性是指標型別。原型屬性是物件型別,所以,也可以叫原型物件,原型就是模子,模型。函式何來原型,其實理解原型 ( 模型 ) 更應該用建構函式來理解會更好。

  建構函式是用來構造例項的,每次用 new 運算子呼叫建構函式產生一個例項時,模型就會起作用。就像我們要造一個塑膠製品 ( 如:杯子,電腦顯示器的外殼,印表機的外殼等 ) ,都有一個模具,只要是同一個模具做出來的物體,都非常相似。所以,百度上對模具的解釋:模具的俗稱。常用於比喻具有大量相似點的兩個或多個人或者事物。

  b) 原型模式建立物件 ( 把建構函式和原型模式合在一起 )

  用同一個建構函式構造的例項,具有很多的共同點 ( 共同的屬性或者函式 ) ,這些共同點就是很多書籍描述的“所有例項共享的屬性和方法”。這些共同點就是用 prototype 屬性進行維護的。具體的做法就是:所有例項共享的屬性和方法用 prototype 屬性進行表示。

  如:

  function Person(id,name,sex){

  // 在建構函式里寫的是每個例項特有的屬性 ( 屬性值不一樣 )

  this.id =id;

  this.name = name;

  this.sex = sex;

  }

  // 所有人的國籍都是中國,國籍屬性就用 prototype 來表示

  Person.prototype.country = “中國” ;

  // 所有人吃的邏輯都一樣。所以,吃的函式也用 prototype 來表示

  Person.Prototype.eat = function(str){

  alert(this.name+ ”在吃” +str+ ”,天在看……” );

  }

  var p1 = new Person( 007 , “樂樂” , “女” );

  var p2 = new Person( 008 , “寶寶” , “男” );

  Console.log(p1.country);// 中國

  Console.log(p2.country); // 中國

  p1 p2 兩個例項的 country 屬性值都是中國,因為它們兩個是一個建構函式例項化出來的 ( 一個模子“刻”出來的 )

  如下是示意圖,其中帶箭頭的線表示指向。

02

  圖中可以看出:

  1) 、在 Person 建構函式的 prototype 屬性中有個 constructor 屬性,指向了建構函式本身。 constructor 屬性到底有何用,大家先把它 save 到大腦中,後面給大家講解。

  2) 、兩個例項 p1 p2 指向了 Person 建構函式的 prototype 屬性,跟 Person 建構函式沒有直接關係。

  3) 、兩個例項 p1 p2 都有 [[prototype]] 屬性。例項靠著 [[prototype]] 屬性找到它所對應建構函式的原型,也是靠它來找到,原型中的屬性的。注意, [[prototype]] 屬性不能直接在程式碼中使用。

  c) 原型 ( 型別的 ) 屬性和例項 ( 型別的 ) 屬性

  每個例項特有的屬性和方法存放在例項所在記憶體區域,也叫例項屬性,如以上例中的 id name sex 屬性。所有例項共享的屬性和方法,都在原型 (prototype) 對應的記憶體區域,也叫原型的屬性,如上例中的 country

  i. 原型 ( 型別的 ) 屬性變成例項 ( 型別的 ) 屬性

  這裡有點疑惑,隨著時間的推移,有的物件的原型屬性的值會發生變化 ?

  如:寶寶年輕時,覺得俄羅斯的美女多,決定定居俄羅斯了。即 p2 country( 國籍 ) 的值為俄羅斯。那該如何是好,改還是不改 ? 改了會不會影響其它物件的 country 屬性的值。不改,又不能滿足需求。看來, JAVASCRIPT 在這方面還是考慮到了。可以改,而且不會影響其它物件的屬性值。

  還有,如果出現了例項屬性和原型屬性重名的情況,用例項來訪問該屬性時,到底訪問的是例項屬性還是原型屬性。這個 JAVASCRIPT 中解決了。

  如何解決上面的問題的。在 JAVASCRIPT 中,當給原型屬性賦值時,在對應例項中會增加了一個同名的例項屬性,然後把值賦給例項屬性,而原型屬性的值不受影響。當訪問該屬性時,先在例項屬性中尋找,如果找不到,再在原型屬性中找。

  如以下程式碼:

  P2.country = “俄羅斯” ;

  執行時,記憶體會變成如下:

03

  在 p2 的例項中增加一個 country 例項屬性,內容為“俄羅斯” ( 圖中紅色的框裡 ) 。這樣,程式碼 p1.country 依然去找例項屬性的值“中國”。而 p2.country 先在例項屬性中找 country ,找到了,就不用去原型屬性中去找了。即,當例項訪問屬性時,會先在例項的記憶體中去尋找,如果找不到就會到原型的記憶體中去尋找。

  ii. 刪除例項 ( 型別的 ) 屬性

  隨著寶寶年齡的增長,對美女沒有了興趣,而且覺得還是在自己的國家好,又想回來。即 p2.country 的值為”中國”,這時候是可以利用原型裡的屬性值,怎麼辦 ? 沒事,使用 delete p2.country 就會把 p2 的例項屬性 country 刪除掉。

  放心吧, delete 是不能刪除掉原型的屬性的。

  3 、 繼承時原型的理解 ( 原型鏈 )

  原型鏈是 ECMAScript 中實現繼承的一種方式。如果不懂繼承,請先百度,理解繼承的概念。

  原型繼承的基本思想是讓原型屬性 ( 物件 ) 指向另外一個型別的的例項。

  如:

  父物件:人

  function Person(id,name,age){

  this.id = id;

  this.name = name;

  this.age = age;

  }

  Person.prototype.eat = function(str){

  alert(this.name+" 在吃 "+str);

  }

  子物件:程式設計師

  function Programmer(languages){

  this.languages = languages;

  }

  // 此句話使用原型實現了繼承,子物件 Programmer 的原型屬性指向了父物件 Person 的例項。

  Programmer.prototype = new Person( 008 , “寶寶” , 20 );

  Programmer.prototype.writeCode=function(){

  alert(this.name+" 一邊努力地寫著程式碼,一邊想著‘多寫程式碼,多掙錢’ ");

  }

  從圖中可以看出,子物件 Programmer 擁有了父物件的屬性 (id name age) 和方法 (eat) 。自己特有的屬性 languages 和方法 writeCode() 。成功完成了繼承。

  特別要注意,子物件完成了繼承關係後,再給子物件的原型中增加屬性和方法。即,先寫程式碼 Programmer.prototype = new Person( 008 , “寶寶” , 20 ); 再寫程式碼:

  Programmer.prototype.writeCode=function(){

  alert(this.name+" 一邊努力地寫著程式碼,一邊想著‘多寫程式碼,多掙錢’ ");

  }

  否則,當子物件的 prototype( 原型 ) 屬性的指向發生變化後,原來在 prototype( 原型 ) 屬性中所寫屬性和方法就會丟失。

  原型鏈繼承:當 B 物件的原型屬性指向了 A 物件的例項,而 C 物件的原型屬性指向 B 物件的例項時,就完成了原型鏈繼承。

  注:

  1 、此篇文章可以結合 JAVASCRIPT 中建立物件的幾種方式進行學習。如果再能結合上篇文章《對比引用型別與基本型別》就會更好

  2 、此篇文章只是為了理解 prototype 屬性,所以,很多的注意點並沒有涉及。作者更希望大家學一點,理解一點,而不是大而全。而且學習是循序漸進的。先把 prototype 屬性理解了,再去關注注意點。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2639991/,如需轉載,請註明出處,否則將追究法律責任。

相關文章