Javascript繼承的最佳實務
什麼是繼承?
繼承是物件導向最顯著的一個特性。繼承是從已有的類中派生出新的類,新的類能吸收已有類的資料屬性和行為,並能擴充新的能力。
在Javascript 中 沒有 類的概念, 它是通過建構函式來產生 對象,
建構函式 就是一個普通的函數,通常當函數名 為 大寫開頭的,我們認為是建構函式,否則 就是普通的方法。
function A() { this.name = 'A Class instance';}function m1() {}
既然 Javascript 是 通過建構函式來產生 對象,那我們怎麼定義它的 屬性、方法呢?
var a1 = new A(); 是新建立一個A類對象,預設情況下,在建構函式中,使用this指向的是 新建立的對象;
而Javascript的對象屬性 可以 晚綁定,即
var obj = {};obj.name = 'obj1';obj.say = function say() { console.log(this.name);}可以先產生對象,在需要增加屬性時, 通過 obj.屬性名稱 或 obj['屬性名稱'] 來添加屬性。
所以我們在建構函式中 使用 this.屬性名稱 來 定義產生的 對象 的 屬性和方法。
function A() { this.name = 'A Class instance'; this.say = function() { console.log('Hi,I am ' + this.name); }}var a1 = new A();var a2 = new A();a1.say(); // Hi,I am A Class instancea2.say(); // Hi,I am A Class instance
我們分析一下上面代碼,
建立了 a1,a2 對象,在建立a1,a2 對象的時候 都為其添加一個say()方法,而這2個對象的 say方法 完全一樣,
試想想 如果 建立n 個 A類對象,那是不是為這n個對象 添加一個say()方法,那是非常浪費記憶體。
所以在Javascript 中 引用了 prototype 原型的概念:
每一個建構函式都有一個prototype 對象,使用建構函式執行個體化一個對象,訪問這個對象屬性時,如果這個對象有該屬性,則返回,否則就會在該對象的建構函式的prototype 上找,直到找到就返回,否則返回的是undefined
來驗證一下:
在上面代碼中,A建構函式中沒有定義say 方法,
但a1,a2 卻 能夠 調用say()方法,因為 A函數的prototype 預設指向的是 Object.prototype ;<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+tMvKscTatObW0Na7saO05k9iamVjdC5wcm90b3R5cGUuc2F5LLb4QbL6yfq1xLbUz/MgysfNqLn91K3Qzbv61sajrNK7suPSu7LjzfnJz9XSo6zIu7rztffTw7XEoaM8L3A+CjxwPjxicj4KPC9wPgo8cD7L+dLUzai5/SBwcm90b3R5cGXUrdDNu/rWxqOsztLDx7/J0tTKtc/WtPrC67i008OjrLrNvMyz0KGjPC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">A.prototype.say = function() { console.log('Hi,I am ' + this.name);}function A() { this.name = 'A Class instance';}var a1 = new A();var a2 = new A();a1.say(); // Hi,I am A Class instancea2.say(); // Hi,I am A Class instancefunction B() { this.name = 'B Class instance';}B.prototype = new A();B.prototype.constructor = B;var b = new B();b.say();
分析一下上面代碼 執行結果:
我們定義了一個B類,並把他的prototype 指向 A的執行個體對象,
然後產生一個 b 對象,調用b對象 say() ,也輸出了內容。
這是為什麼呢?
訪問 b 對象屬性時, 如果不存在 ,就會在其 prototype 訪問,
就是 訪問a 對象的 prototype ,但a對象 prototype 預設 是 指向Object.prototype 的,
而我們在 Object.prototype 定義了say 方法,b 對象也能訪問 say()方法, 就好像b 繼承了 父類中的 屬性一樣。
這裡我們也可以看出,一旦 原型鏈 過長,會導致 訪問多個對象的prototype。
所以 在設計 的時候 應該 不超過 3層原型鏈,可以考慮其他方式。
Javascript 最佳的實踐:
A.prototype.say = function() { console.log('Hi,I am ' + this.name);}function A() { this.name = 'A Class instance';}通過原型對象,添加方法,
通過建構函式 定義 對象的 屬性。
繼承還可以有很多種 實現方式, 比如 屬性的複製等等,應當靈活運用。