Javascript中的原型

首先要明確的是,

  1. js中的原型是一個對象,而且這個對象是函數(對象)的一個屬性,即prototype。
  2. 當以構造函數的形式調用函數時,即new一個函數,會創建一個實例對象,這個實例的__proto__屬性會指向構造函數的prototype,由於原型也是對象,所以它也有一個__proto__屬性,這個屬性指向的是原型對象的構造函數的prototype,這樣一步一步上溯到Object.prototype,Object.prototype對象的__proto__指向的是null,這就形成了一個鎖鏈一樣的東西,稱爲原型鏈。如果把原型鏈看做一條河流那麼null就是源頭了。注意原型prototype是函數的屬性而不是實例的。
  3. 當一個函數被創建時,Function構造器產生的函數對象會執行類似的代碼:this.prototype = {constructor: this}

下面我們用代碼來闡述一下上面的結論,假設有這樣一段代碼:

var Flower = function(name) {this.name = name;}
var f = new Flower("flower");

那麼這段代碼的原型鏈是什麼樣子的呢?

這裏寫圖片描述

原型鏈爲圖中紅色虛線,我們用代碼驗證下我們的猜想,

// true
f.__proto__ === Flower.prototype;
// true;
Flower.prototype.__proto__ === Object.prototype;
// true
Object.prototype.__proto__ === null;

如果把原型鏈看做一條河流,那麼null那一端就是上游,另一端爲下游。我們都知道河流是有方向的,水只能由上游流向下游,而不能相反。

那麼這個原型鏈有什麼作用呢?它是js繼承系統的基礎。上面提到,原型也是一個對象,既然是對象就可以擁有屬性和方法,但是這個對象有點特殊,如果你往這個對象裏添加了屬性和方法,處於下游的對象包括原型都會擁有這個屬性和方法,甚至會影響到已有的對象。這有點像你往河裏面導入一瓶墨水,那麼下游很快就會被染上顏色。

還是老樣子,用代碼驗證下,

Object.prototype.nishishui = "wo"
// "wo"
Flower.prototype.nishishui
// "wo"
Flower.nishishui
// "wo"
f.nishishui
// "[object Object]"
f.toString()

我們從來沒有在Flower和f上定義nishishui這個屬性,但是它們都可以訪問到。這是怎麼回事呢,實際上當f調用nishishui這個屬性時,首先檢查自身,當然沒有,然後通過__proto__去Flower.prototype中去找發現也沒有,最後,以同樣的方法找到Object.prototype,發現這小子原來在這裏,當然不能放過了。js正是通過這種方式實現自己的繼承,例如上面的toString()方法。不過如果原型鏈過長,會有潛在的性能問題,這個以後再說吧。

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