一、什么是繼承?
繼承是面向對象語言的一個重要概念。許多面向對象語言都支持兩種繼承方式:接口繼承和實現繼承;接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。由於函數沒有簽名,所以ECMAScript只支持實現繼承,而實現繼承主要是依靠原型鏈來實現的。
二、繼承的多種方法分析
(一)原型繼承
基本思想:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法;
1 function Animal() { 2 this.species = '動物' 3 this.colors = ['白色'] 4 } 5 function Cat(name, eat) { 6 this.name = name 7 this.eat = eat 8 } 9 Cat.prototype = new Animal() 10 var cat1 = new Cat('貓', '老鼠') 11 console.log(cat1.species) //動物 12 console.log(cat1.colors) //['白色']
存在的問題:
cat1.colors.push('黑色') cat1.colors //['白色', '黑色'] cat2.colors //['白色', '黑色']
當tCat通過原型鏈繼承了Animal后,Cat.prototype就變成了Animal的一個實例,因此它也擁有了一個自己的colors屬性,結果:Cat的所有的實例都會共享colors屬性;
(二)構造函數繼承
基本思想:在子類型構造函數的內部調用超類型構造函數。函數只不過是在特定環境中執行代碼的對象,因此可通過使用call()和apply()在新創建的對象上執行構造函數
1 function Cat(name, eat) { 2 3 Animal.apply(this, arguments) 4 this.name = name 5 6 this.eat = eat 7 8 } 9 10 var cat1 = new Cat('貓', '魚') 11 12 console.log(cat1.species) //動物 13 cat1.colors.push('黑色') 14 console.log(cat1.colors) //['白色', '黑色'] 15 var cat2 = new Cat('貓', '貓糧') 16 console.log(cat2.colors) //['白色']
存在問題:方法都在構造函數中定義,所以沒法利用函數的復用;並且在超類型的原型中定義的方法對於子類型而言是不可見的。
function Animal() { this.species = '動物' this.colors = ['白色'] } Animal.prototype.getColor = function() { return this.colors } function Cat(name, eat) { Animal.apply(this, arguments) this.name = name this.eat = eat } var cat1 = new Cat('貓', '魚') cat1.getColor() //報錯:cat1.getColor is not a function
(三)組合繼承
基本思想:使用原型鏈實現對原型屬性和方法的繼承,而通過構造函數實現對實例屬性的繼承;
function Animal(species) { this.species = species this.colors = ['白色'] } Animal.prototype.getColor = function() { console.log(this.colors) } function Cat(name, eat) { //繼承屬性 this.name = name this.eat = eat Animal.call(this, name) } //繼承方法 Cat.prototype = new Animal() Cat.prototype.concatructor = Cat Cat.prototype.sayName = function() { console.log(this.name) } var cat1 = new Cat('貓', '吃魚') cat1.colors.push('黑色') console.log(cat1.colors) //['白色', '黑色'] cat1.getColor() //['白色', '黑色'] cat1.sayName() //'貓' var cat2 = new Cat('波斯貓', '吃貓糧') console.log(cat2.colors) //['白色'] cat2.getColor() //['白色'] cat2.sayName() //'波斯貓'