全网最详细对小白最友好的原型继承之组合继承

30 阅读2分钟
// 组合继承之三
/*
组合继承就是将原型链和借用构造函数的技术结合到一起,
背后思想是使用原型链实现对方法的继承,
通过借用构造函数实现对属性的继承。
这样,既能够保证能够通过原型定义的方法实现函数复用,
又能够保证每个实例有自己的属性。
*/
// 1.老规矩先创建一个父级函数
function Parent(name) {
  this.name = name
  this.children = ['a', 'b']

  /*这里有个函数看下面就知道了
  this.getName = function(){
  return this.name
}
  */
}
// 2.接着我给父级函数的原型添加一个函数
Parent.prototype.getName = function () {
  return this.name
}
// 3.然后我创建一个子集函数
function Child(name) {
  // 继续把name绑定如果不理解请看主页前面文章
  Parent.call(this, name)
}

// 4.好了我开始实例化Parent到Child原型上
Child.prototype = new Parent()

// 5.我把Child赋值给自己constructor然后就完成继承了
Child.prototype.constructor = Child

// 6.开始创建一个实列来检测
let child1 = new Child('C1')
// 8.children添加CC
child1.children.push('CC')
// 然后输出看看得到什么
console.log('child1', child1.name, "==", child1.children)
//  C1 == ['a', 'b', 'CC']  很成功的传值C1 和添加CC

// 9.接下来再创建一个实例检测

let child2 = new Child('C2')

// 10.给children添加CC2
child2.children.push("CC2")
// 看看得到什么结果吧
console.log('child2', child2.name, "==", child2.children)
// C2 ==  ['a', 'b', 'CC2'] 看C2也成功传参然后是CC2成功添加
// 再看看child1会不会被改变呢,毕竟child2并没有看到有之前child1添加进去的CC,
// 所以理论上这个也不会有改变
console.log('child1', child1.name, "==", child1.children)
//  C1 == ['a', 'b', 'CC'] 很不错没有改变

// 11.然后看看控制台输出分析优缺点
console.log(child2);
/*
   >Child {name: 'C2', children: Array(3)}
    >children: (3) ['a', 'b', 'CC2']
     name: "C2"
     >[[Prototype]]: Parent
      > children: (2) ['a', 'b']
      > constructor: ƒ Child(name)
        name: undefined
     >[[Prototype]]: Object
*/

/*
总结:
组合继承既具有原型链继承能够复用函数的特性,
又有借用构造函数方式能够保证每个子类实例能够拥有自己的属性以及向超类传参的特性,
但组合继承也并不是完美实现继承的方式,因为这种方式在创建子类时会调用两次超类的构造函数。
也就是这个内容
>[[Prototype]]: Parent
  > children: (2) ['a', 'b']
  > constructor: ƒ Child(name)
    name: undefined
 >[[Prototype]]: Object
  >getName: ƒ ()
  >constructor: ƒ Parent(name)
  >[[Prototype]]: Object

  缺点:父类构造函数的重复调用执行,会造成浪费,如果父类构造函数共有属性极多,会导致运行速度减慢。
       父类的属性会在原型上多加一次。
*/