2012-10-18 120 views
1

我發現這是最推薦的方式來在javascript中進行繼承。javascript繼承模式混淆

function extend(Child, Parent) { 
var F = function(){}; 
F.prototype = Parent.prototype; 
Child.prototype = new F(); 
} 

如果我已經有孩子的原型中的方法,他們不會覆蓋,我們不應該保存它們。

function extend(Child, Parent) { 
var c = child.prototype; 
var oldProto = new C(); 
var F = function(){}; 
F.prototype = Parent.prototype; 
Child.prototype = new F(); 
for(var i in oldProto){ 
    Child.prototype[i] = oldProto[i] 
} 
} 
+0

_「如果我已經有孩子的原型方法」 _ - 不這樣做。 – Alnitak

+0

@Alnitak如果我願意繼承 擴展(人類,猴子)比擴展(人類,驢子)怎麼樣。難道你不會失去所有的猴子屬性 –

+0

多重繼承? - 不要這樣做;-) – Alnitak

回答

0

你試圖實現的模式叫做multiple inheritance。由於您遇到的問題,這個問題極不推薦使用,稱爲鑽石問題。改爲使用mixin pattern

+0

這與_deadly diamond_-thing沒有任何關係。他的問題是,通過擴展,Child.prototype.methodx將會丟失,因爲Child.prototype被重新分配給Parent的一個實例。他需要'Parent'的方法,而不會丟失分配給'Child.prototype'的那些方法。順便說一句:JavaScript不支持多繼承,只支持原型鏈接 –

+0

@EliasVanOotegem在niteshsharma的評論中,您可以看到他正在嘗試執行多重繼承。 – bjornd

+1

@bjornd你是對的。他試圖實現多重繼承,但在像JS這樣的原型語言中,鑽石問題並不存在,因爲它只是「繼承」的方法,而不是實例數據。 – Alnitak

2

我不確定這對你有什麼好處,但要記住它很重要:原型與類不同。你正在做的是試圖讓JS像傳統的面嚮對象語言一樣行事,這種語言試圖教海豚跳芭蕾舞,或者迫使老虎變成純素食者:令人欽佩,但註定會流淚。

我真的不明白爲什麼你想使用extend函數來做任何你想做的事情。爲什麼不簡單地使用這個:

function Parent() 
{}; 
function Child() 
{}; 
//augment parent proto 
Parent.prototype.parentMethod1 = function() 
{}; 
//set Child's proto to Parent 
Child.prototype = new Parent(); 
Child.prototype.constructor = Child; 
//Then augment the Child's prototype 
Child.prototype.childMethod1 = function() 
{}; 
var foo = new Child(); 
foo.parentMethod1();//works 
foo.childMethod1();//works, too 

IMO,這完全解決了這個問題。當然,這有點冗長,但OOP始終是。

+0

「你正在做的是試圖讓JS像傳統的面嚮對象語言一樣行事,它試圖教海豚跳芭蕾舞,或者迫使老虎變成純素」順便說一句,谷歌在他們的許多網站應用程序http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/base.js#1423 – bjornd

+0

@bjornd:_Success_是一個相對術語。當然,你可以實現這些功能。但事實上,我不喜歡這樣的構造:他們在直接的方法到原型分配場景中模仿多重繼承的方式,但如果你的原型方法是IIFE的返回值,那該怎麼辦......老實說,很多的人正在與封閉的事情鬥爭,我不敢想他們會怎樣做GC封閉變量,在_「擴展」_原型方法中引用......底線:從理論上講,谷歌代碼的工作原理是使用可能會導致頭痛。我同意Alnitak:不要。 –

+0

經常使用的一個短語是用於工作的正確工具。當你試圖強制JS像另一種語言一樣行事時,你應該考慮使用不同的語言(這不是一種真正的選擇)或評估工具(JS)。儘管如此,JS仍然有很多不足之處。如果有更多的人真正知道JS能夠勝任的話,我會喜歡它。它是一種功能性語言,而不是傳統的OO語言:相應地使用它 –

0

下面的代碼是我在JavaScript中繼承的最好的代碼之一。

Object.create(proto [,propertiesObject])在MDN here上討論。

下面,Jon定義了一個名爲ExtendBase的基本空對象,然後添加了一個名爲extend的函數屬性,它不是枚舉型的,它的參數是一個新的對象。

該對象應該包含可枚舉的屬性,例如將被添加到基礎對象的方法和數據。

他從傳遞的對象中獲取所有可枚舉的屬性,然後使用這些屬性的名稱創建必要描述符的數組以傳遞到Object.create。然後,他使用父對象作爲原型,並將結果描述符作爲新屬性直接添加到Object.create()調用中的子對象。如你所見,你可以使用帶有屬性的對象參數(包括方法)來擴展一個父對象,而不會丟失該對象的屬性,結果是一個父對象作爲原型的子對象,而對象的可枚舉對象傳遞的對象直接添加到孩子。

然而,這樣可保持整潔原型鏈,而打算使用被三立創建的其他對象父延伸到一個新的孩子在某種程度上是有道理的,延長的父對象:

現場樣品here(按F12在Chrome控制檯輸出,或在Firefox使用Firebug等)

的JavaScript:

// Original Author: FireFly - Jonas Höglund - ##javascript channel 
// on irc.freenode.net - see THANKS File. Updated to private data 
// members and passable initial parameters by Scott Sanbar 

/////////////// 
// Library code 
/////////////// 

var ExtendBase = {}; 

Object.defineProperty(ExtendBase, 'extend', { 
    enumerable:false, value:function (obj) { 
     'use strict'; 

     var descs = {}; 

     Object.getOwnPropertyNames(obj).forEach(function (key) { 
      descs[key] = Object.getOwnPropertyDescriptor(obj, key) 
     }); 

     return Object.create(this, descs); 
    } 
}); 

/////////////// 
// Sample Usage 
/////////////// 

function PersonObj(nam) { 

    return { 
     name:new function() { 

      var name = nam; 

      this.set = function (value) { 
       name = value; 
      }; 

      this.get = function() { 
       return name; 
      } 
     }, 

     // A person can tell you its name. 
     talk:function() { 
      return "Hello, I'm " + this.name.get(); 
     } 
    } 
} 
; 

function WorkingPersonObj(occ) { 

    return { 

     occupation:new function() { 

      var occupation = occ; 

      this.set = function (value) { 
       occupation = value; 
      }; 

      this.get = function() { 
       return occupation; 
      } 
     }, 

     // A working person also tells you their occupation when they talk. 
     talk:function() { 
      return Person.talk.call(this) + " and I am a " + this.occupation.get(); 
     } 
    } 
} 
; 

var hush = { 

    hush:function() { 
     return "I am supposed to be quiet"; 
    } 
}; 

var Person = ExtendBase.extend(new PersonObj('Harry')); 
var WorkingPerson = Person.extend(new WorkingPersonObj('wizard')); 

var wp1 = WorkingPerson.extend(hush); 

console.log(wp1.talk()); // "Hello, I'm Harry and I am a wizard" 
console.log(wp1.hush()); // "I am supposed to be quiet" 
wp1.name.set("Elijah"); 
wp1.occupation.set("prophet"); 
console.log(wp1.talk()); // "Hello, I'm Elijah and I am a prophet" 
console.log(wp1.name.get()); 
console.log(wp1.occupation.get());