這篇文章帶給大家的內容是關於JS中原型式和寄生式繼承的詳解(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
前言:最近在細讀Javascript高階程式設計,對我而言,中文版,書中很多地方翻譯的差強人意,所以用自己所理解的,試著解讀下。如有紕漏或錯誤,會非常感謝您的指出。文中絕大部分內容引用自《JavaScript高級程式設計第三版》。
道格拉斯 克勞福德在2006年寫了一篇文章,題為Prototypal Inhertitance in JavaScript(JavaScript中的原型式繼承)。
在這篇文章中,他介紹了一種實作繼承的方法,這種方法並沒有使用嚴格意義上的建構子。
他的想法是藉助原型可以基於現有的對象創建新對象,同時還不必因此創建自訂類型。
為了達到這個目的,他給瞭如下函數。
function object(o) { function F(){}; F.prototype = o; return new F(); }
在object()函數內部,先建立一個臨時性的建構函數,然後將傳入的物件作為這個建構函數的原型,最後傳回了這個臨時型別的一個新實例物件。
從本質上講,object()對傳入的物件執行了一次淺複製。
function object(o){ function F(){}; F.prototype = o; return new F(); } var person = { name: "Shaw", friends: ["Sharon", "Sandy", "Van"] } var person1 = object(person); /* person1 = function object(person){ function F(){}; F.prototype = person1; return new F(); }() person1 = function object({ name: "Shaw", friends: ["Sharon", "Sandy", "Van"] }){ function F(){}; F.prototype = { name: "Shaw", friends: ["Sharon", "Sandy", "Van"] } return { } } person1 = { }; {}.__proto__ = { name: "Shaw", friends: ["Sharon", "Sandy", "Van"] } */ person1.name = "Roc"; person1.friends.push("Roster"); var person2 = object(person); person2.name = "Linda"; person2.friends.push("Jobs"); console.log(person.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"] console.log(person1.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"] console.log(person2.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"]
克羅克福德主張的這種原型式繼承,要求你必須有一個物件可以作為另一個物件的基礎。
如果有這麼一個物件的話,可以把它傳給object()函數,然後再根據具體需求對得到的物件加以修改即可。
ECMAscript5透過新增Object.create()方法規範了原型式繼承。
這個方法接收兩個參數: 一個用作新物件原型的物件和(可選的)一個為新物件定義額外屬性的物件。
在傳入一個參數的情況下,Object.create()與object()方法的行為相同。
var person = { name: "Shaw", friends: ["Sharon", "Sandy", "Van"] } var person1 = Object.create(person); person1.name = "Roc"; person1.friends.push("Roster"); var person2 = Object.create(person); person2.name = "Linda"; person2.friends.push("Messi"); console.log(person.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"] console.log(person1.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"] console.log(person2.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"]
Object.create()方法的第二個參數與Object.defienProperties()方法的第二個參數格式相同:
每個屬性都是透過自己的描述子定義的。
以這種方式指定的任何屬性都會覆寫原型物件上的同名屬性。
var person = { name: "Shaw", friends: ["Sharon", "Sandy", "Selina"] } var person1 = Object.create(person, { name: { value: "Roc" } }) console.log(person1.name); //"Roc"
支援Object.create()方法的瀏覽器有IE9 , Firefox 4 , Opera 12 和 Chrome。
適用場景:
在沒有必要興師動眾地創建建構函數,而只想讓一個物件與另一個物件保持類似的情況下,原型繼承是完全可以勝任的。
千萬要記住,包含引用類型值的屬性總是會共用對應的值,就像使用原型模式一樣。
寄生式(parasitic)繼承是與原型式繼承緊密相關的一種思路,並且也是由大神克勞克福推而廣之的。
寄生式繼承的想法與寄生建構子和工廠模式類似。
創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最後再像真地是它做了所有工作一樣返回對象。
function object(o){ function F(){}; F.prototype = o; return new F(); } function createAnother(original) { var clone = object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 console.log("hi"); } return clone; //返回这个对象 }
在這個例子中, createAnother()函數接收了換一個參數,也就是將要作為新物件基礎的物件。
然後,把這個物件參數(original)傳遞給object()函數, 將傳回的結果賦值給clone。
再為clone物件新增一個新方法sayHi(),最後回傳clone物件。
可以像下面這樣來使用createAnother()函數:
function object(o){ function F(){}; F.prototype = o; return new F(); } function createAnother(original) { var clone = object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 console.log("hi"); } return clone; //返回这个对象 } var person = { name: "Shaw", friends: ["Sandy", "Sharon", "Van"] } var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
這個範例中的程式碼是基於person傳回一個新物件-anotherPerson。新物件不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法。
在主要考慮物件而不是自訂類型和建構函數的情況下,寄生式繼承也是一種有用的模式。
前面示範繼承模式時使用的object()函數不是必需的,任何能夠傳回新物件的函數都適用於此模式。
以上是JS中原型式和寄生式繼承的詳解(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!