1 function Supertype () { 2 this.property = true 3 } 4 5 Supertype.prototype.getSuperValue = function () { 6 return this.property 7 } 8 9 function SubType () { 10 this.subproperty = false 11 } 12 13 // 繼承了SuperType 14 SubType.prototype = new Supertype() 15 16 SubType.prototype.getSubValue = function () { 17 return this.subproperty 18 } 19 20 var instance = new SubType() 21 console.log(instance.getSuperValue())
原型鏈的問題:函數
1 function SuperType (name) { 2 this.name = name 3 } 4 5 function SubType () { 6 // 繼承了SuperType,同時還傳遞了參數 7 SuperType.call(this, 'Nicholas') 8 9 // 實例屬性 10 this.age = 29 11 } 12 13 var instance = new SubType() 14 console.log(instance.name) 15 console.log(instance.age)
借用構造函數的問題:this
組合繼承是將原型鏈和借用構造函數的技術組合到一塊,取其兩者之長。spa
1 function SuperType (name) { 2 this.name = name 3 this.colors = ['red', 'blue', 'green'] 4 } 5 6 SuperType.prototype.sayName = function () { 7 console.log(this.name) 8 } 9 10 function SubType (name, age) { 11 // 繼承屬性 12 SuperType.call(this, name) 13 14 this.age = age 15 } 16 17 // 繼承方法 18 SubType.prototype = new SuperType() 19 SubType.prototype.constructor = SubType 20 SubType.prototype.sayAge = function () { 21 console.log(this.age) 22 } 23 24 var instance1 = new SubType('Nicholas', 29) 25 instance1.colors.push('black') 26 console.log(instance1.colors) // "red,blue,green,black" 27 instance1.sayName() // "Nicholas" 28 instance1.sayAge() // 29 29 30 var instance2 = new SubType('Greg', 29) 31 console.log(instance2.colors) // "red,blue,green" 32 instance2.sayName() // "Greg" 33 instance2.sayAge() // 29
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優勢,成爲Javascript中最經常使用的繼承模式。prototype
道格拉斯·克羅克福德介紹了一種實現繼承的方法,這種方法並無使用嚴格意義上的構造函數。他的想法是藉助原型能夠基於已有的對象建立對象,同時還沒必要由於建立自定義類型。code
1 function object (o) { 2 function F() {} 3 F.prototype = o 4 return new F() 5 }
ECMAScript 5經過新增Object.create()方法規範了原型式繼承。這個方法接收兩個參數:一個用做新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象。對象
1 var person = { 2 name: 'Nicholas', 3 friends: ['Shelby', 'Court', 'Van'] 4 } 5 6 var anotherPerson = Object.create(person, { 7 name: { 8 value: 'Greg' 9 } 10 }) 11 12 console.log(anotherPerson.name) // "Greg"
1 function createAnother (original) { 2 var clone = object(original) // 經過調用函數建立一個新對象 3 clone.sayHi = function () { // 以某種方式來加強這個對象 4 console.log('hi') 5 } 6 return clone // 返回這個對象 7 }
1 var person = { 2 name: 'Nicholas', 3 friends: ['Shelby', 'Court', 'Van'] 4 } 5 6 var anotherPerson = createAnother(person) 7 anotherPerson.sayHi() // "Hi"
前面說過,組合繼承式JavaScript最經常使用的繼承模式。但它也有本身的不足,組合繼承最大的問題就是不管什麼狀況下,都會調用兩次超類型構造函數:一次是在建立子類型原型的時候,另外一次是在子類型構造函數內部。blog
1 function SuperType (name) { 2 this.name = name 3 this.colors = ['red', 'blue', 'green'] 4 } 5 6 SuperType.prototype.sayName = function () { 7 console.log(this.name) 8 } 9 10 function SubType (name, age) { 11 SuperType.call(this, name) // 第二次調用SuperType() 12 13 this.age = age 14 } 15 16 // 繼承方法 17 SubType.prototype = new SuperType() // 第一次調用SuperType() 18 SubType.prototype.constructor = SubType 19 SubType.prototype.sayAge = function () { 20 console.log(this.age) 21 }
所謂寄生組合式繼承,即經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法。其背後的基本思路是:沒必要爲了指定子類型的原型而調用超類型的構造函數,咱們所須要的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,而後再將結果指定給子類型的原型。寄生組合式繼承的基本模式以下所述。繼承
1 function inheritPrototype(subType, superType) { 2 var prototype = object(superType.prototype) // 建立對象 3 prototype.constructor = subType // 加強對象 4 subType.prototype = prototype // 指定對象 5 }
1 function SuperType (name) { 2 this.name = name 3 this.colors = ['red', 'blue', 'green'] 4 } 5 6 SuperType.prototype.sayName = function () { 7 console.log(this.name) 8 } 9 10 function SubType (name, age) { 11 SuperType.call(this, name) 12 13 this.age = age 14 } 15 16 inheritPrototype(subType, superType) 17 18 SubType.prototype.sayAge = function () { 19 console.log(this.age) 20 }