面向對象的JavaScript 三 ----- prototype

本文主要介紹javascript中另文容易產生誤解和誤用的prototype屬性。

prototype是functions對象的屬性,也是在javascript中實現繼承的面向對象機制的關鍵,所以有必要弄懂prototype屬性。
首先看看一個普通對象的prototype屬性是什麼:
>>> typeof foo.prototype
       "object"
看來所有對象最終都是繼承object的,這和java等語言一樣。
通過prototype可以給function加上函數和屬性。
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function() {
  return 'Rating: ' + this.rating + ', price: ' + this.price;
};
或者,用下面這種寫法:
Gadget.prototype = {
  price: 100,
  rating: 3,
  getInfo: function() {
    return 'Rating: ' + this.rating + ', price: ' + this.price;
  }
};
使用prototype增加屬性,該屬性是不會拷貝到每個function實例的.這個表示,你可以修改一個function實例的prototype屬性,這個修改會作用到所有實例上.這有點類似java中的類的static成員變量。

接下來看一個實例,讓你理解js engine在查找prototype屬性的方法:
function Gadget(name) {
  this.name = name;
}
Gadget.prototype.name = 'foo';    
>>> var toy = new Gadget('camera');
>>> toy.name;
       "camera"

>>> delete toy.name;
     true
>>> toy.name;
     "foo"
如果訪問的是prototype 屬性,js 回找不到,然後會找到constructor的prototype。所以在delete後,第二次調用name返回的是“foo”

那麼如何遍歷得到一個對象的prototype屬性呢?可以這樣:
for (var prop in newtoy) {
  console.log(prop + ' = ' + newtoy[prop]);
}
如果你想區分prototype屬性,可以這樣寫:
如果你想區分,可以使用:
>>> newtoy.hasOwnProperty('name')
     true
>>> newtoy.hasOwnProperty('price')
     false
或者合在一起:
for (var prop in newtoy) {
  if (newtoy.hasOwnProperty(prop)) {
    console.log(prop + '=' + newtoy[prop]);
  }
}

每個對象還有isPrototypeOf方法,作用如下:
var monkey = {  
  hair: true,  
  feeds: 'bananas', 
  breathes: 'air'
};
function Human(name) {  
  this.name = name;
}
Human.prototype = monkey;
>>> var george = new Human('George');
>>> monkey.isPrototypeOf(george)
      true
這個是不是讓你想到繼承。在之後的文章裏我會詳細講解繼承部分。

最後介紹一個很有趣的東西,看看下面的代碼:
>>> function Dog(){this.tail = true;}
>>> var benji = new Dog();
>>> var rusty = new Dog();

>>> Dog.prototype.say = function(){return 'Woof!';}

>>> benji.say();
     "Woof!"
>>> benji.constructor;
   Dog()
現在一切都很正常。

但是我們在做一點試驗
>>> benji.constructor.prototype.constructor
       Dog()
現在讓我們覆蓋prototype
>>> Dog.prototype = {paws: 4, hair: true};
然後調用試試
>>> typeof benji.paws
     "undefned"
>>> benji.say()
     "Woof!"
>>> typeof benji.__proto__.say
       "function"
>>> typeof benji.__proto__.paws
       "undefned"
發現仍舊是舊的prototype,我們新賦值的prototype沒有起到任何作用

現在我們在實例化一個Dog
>>> var lucy = new Dog();
>>> lucy.say()
     TypeError: lucy.say is not a function TypeError: lucy.say is not a function
>>> lucy.paws
    4
>>> typeof lucy.__proto__.say
     "undefned"
>>> typeof lucy.__proto__.paws
     "number"

你會發現:
>>> lucy.constructor
      Object()
>>> benji.constructor
      Dog()
>>> typeof lucy.constructor.prototype.paws
  "undefned"
>>> typeof benji.constructor.prototype.paws
  "number"
很有趣吧,難道你覺得我很無聊?

其實解決這個問題的方法如下:
>>> Dog.prototype = {paws: 4, hair: true};
>>> Dog.prototype.constructor = Dog;
所以,每當你重寫了prototype,最好重置constructor屬性
如果你問我爲什麼,我不知道.

現在你已經有了足夠的javascript知識,下一篇文章將正式開始進入javascript的面向對象世界。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章