原型链继承/借用构造函数继承/组合继承
1. 原型链继承
子类型的原型对象(prototype) = 超类型的实例 new People() 实现继承
构造函数 原型 实例对象 之间的关系
1 //父构造函数 2 function People(gender){ 3 this.name = '父亲'; 4 this.gender = gender; 5 this.goHome = function(){ 6 alert("我回家了") 7 }; 8 this.arr = [1,2,3]; 9 this.corlor = 'red' 10 } 11 People.prototype.eat = function(){ 12 alert("我喜欢吃苹果") 13 } 14 //子构造函数 15 function Child(age){ 16 this.age = age 17 } 18 //子类型的原型对象(prototype) = 超类型的实例 new People() 实现继承 19 Child.prototype = new People(); 20 var child1 = new Child(12); 21 22 console.log(child1.age) // 12 23 console.log(child1.name) // 父亲 24 child1.eat() // 我喜欢吃苹果 25 child1.goHome() // 我喜欢吃苹果 26 27 //修改父类的arr的值(引用类型) 28 child1.arr.push(4); 29 console.log(child1.arr)//[1,2,3,4] 30 31 child1.color = 'blue'; 32 console.log(child1.color)//blue 33 34 //看看修改父类后的实例,也变化了 (引用类型的改变了,基本类型没有这个问题) 35 /** 36 由于包含引用类型值的原型属性会被所有实例共享,而字符串型、数值型则不被共享, 37 所以对 child1.arr 的修改,child2.arr 也会被修改;基本类型没有这个问题 38 **/ 39 var child2 = new Child(); 40 console.log(child2.arr) //[1,2,3,4] 41 console.log(child2.color)//red
问题 : 从上面的代码我们可以实现了子继承了父亲的属性可是却没有办法给父类传参 ,修改父类的引用类型的值的话其他实例也会收到影响。
2. 借用构造函数
通过使用 apply()和 call()方法也可以在(将来)新创建的对象上执行构造函数
1 //父构造函数 2 function People(gender){ 3 console.log(1) 4 this.name = '父亲'; 5 this.gender = gender; 6 this.goHome = function(){ 7 alert("我回家了") 8 }; 9 this.arr = [1,2,3]; 10 this.corlor = 'red' 11 } 12 People.prototype.eat = function(){ 13 alert("我喜欢吃苹果") 14 } 15 //子构造函数 16 function Child(age){ 17 this.age = age; 18 //在子的构造函数里面用call改变this指向实现继承,还可以实现传参 19 //注意的是call函数就会触发,那就造成了每生产一个子都调了一次父类 20 People.call(this,"男人的男人") 21 } 22 var child1 = new Child(12); 23 24 console.log(child1.age) // 12 25 console.log(child1.name) // 父亲 26 console.log(child1.gender) // 男人的男人 27 // child1.eat() // 这个报错 因为没有继承原型上面的方法 28 child1.goHome() // 我回家了
问题:1.虽然解决了传参的问题,可是不能继承父类原型的方法,只能在函数体内定义 2.没有复用可言了,没有继承原型
3.组合继承
指的是将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
//父构造函数 function People(gender){ this.name = '父亲'; this.gender = gender; this.goHome = function(){ alert("我回家了") }; this.arr = [1,2,3]; this.corlor = 'red' } People.prototype.eat = function(){ alert("我喜欢吃苹果") } //子构造函数 function Child(age){ this.age = age; //构造函数继承 People.call(this); } //子类型的原型对象(prototype) = 超类型的实例 new People() 实现继承 Child.prototype = new People(); var child1 = new Child(12); console.log(child1.age) // 12 console.log(child1.name) // 父亲 child1.eat() // 我喜欢吃苹果 child1.goHome() // 我回家了
组合继承避免了原型链和借用构造函数的缺陷(上面的问题都解决了),融合了它们的优点,成为 JavaScript 中最常用的继承模式
因此,使用继承时优先使用组合继承
4. 最后还有一个 寄生继承 (地址给上,也可以了解一下)