492 js的继承:原型继承,CALL继承,寄生组合式继承,ES6中的类和继承

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
  <title>哈哈 - </title>
</head>

<body>
</body>

</html>
<script>
  /*
   * JS本身是基于面向对象开发的编程语言
   *    => 类:封装、继承、多态 
   * 
   * 封装:类也是一个函数,把实现一个功能的代码进行封装,以此实现“低耦合高内聚”
   * 多态:重载、重写
   *    重写:子类重写父类上的方法(伴随着继承运行的)
   *    重载:相同的方法,由于参数或者返回值不同,具备了不同的功能(JS中不具备严格意义上的重载,JS中的重载:同一个方法内,根据传参不同实现不同的功能)
   * 继承:子类继承父类中的方法
   */

  /* 
    public void fn(int x, init y){}
    public void fn(int x){ }

    JavaScript中:
    fn(10, 20); 执行第一个FN
    fn(10); 执行第二个FN
    fn('哈哈'); 报错
  */


  function fn(x, y) {
    console.log(x, y)
  }

  function fn(x) {
    console.log(x)
  }

  fn(10, 20); // 执行第二个FN
  fn(10); // 执行第二个FN


  function fn(x, y) {
    if (y === undefined) {
      // ...
      return;
    }
    // ....
  }
  fn(10);
  fn(10, 20);
</script>


<script>
  /*
   * 在JS语言中,它的继承和其它编程语言还是不太一样的 
   * 继承的目的:让子类的实例同时也具备父类中的私有属性和公共方法
   */

  // JS中第一种继承方案:原型继承(让子类的原型等于父类的实例即可)
  function Parent() {
    this.x = 100;
  }

  Parent.prototype.getX = function getX() {
    return this.x;
  };

  function Child() {
    this.y = 200;
  }

  // => 原型继承 
  Child.prototype = new Parent;
  // console.log(Child.prototype.constructor) // 改变了Child.prototype.constructor指向:ƒ Parent() {this.x = 100;},应该重新指向Child

  Child.prototype.getY = function getY() {
    return this.y;
  };

  let c1 = new Child;
  console.log(c1); // Child {y: 200}
  console.log(c1.y); // 200
  console.log(c1.x); // 100
  console.log(c1.getY()); // 200
  console.log(c1.getX()); // 100


  // -----------------------------------


  // JS中第二种继承方式:CALL继承(只能继承父类中私有的,不能继承父类中公共的)
  function Parent() {
    this.x = 100;
  }

  Parent.prototype.getX = function getX() {
    return this.x;
  };

  function Child() {
    // 在子类构造函数中,把父类当做普通方法执行(没有父类实例,父类原型上的那些东西也就和它没关系了)
    // this -> Child的实例c1
    Parent.call(this); // this.x=100: 相当于强制给c1这个实例设置一个私有的属性x,属性值100,相当于让子类的实例继承了父类的私有的属性,并且也变为了子类私有的属性 “拷贝式”
    this.y = 200;
  }

  Child.prototype.getY = function getY() {
    return this.y;
  };

  let c1 = new Child;
  console.log(c1);


  // -----------------------------------


  // 我们满意的:父类私有的,变成子类私有的;父类公共的,变成子类公共的。
  // JS中第三种继承:寄生组合式继承(CALL继承 + 另类原型继承)
  function Parent() {
    this.x = 100;
  }

  Parent.prototype.getX = function getX() {
    return this.x;
  };

  function Child() {
    Parent.call(this);
    this.y = 200;
  }

  Child.prototype = Object.create(Parent.prototype);
  // 重定向了Child.prototype,重新指向Child
  Child.prototype.constructor = Child;

  Child.prototype.getY = function getY() {
    return this.y;
  };

  let c1 = new Child;
  console.log(c1);


		// 创建一个空对象,让其原型链指向obj
  /* let obj = {
    xxx: 'xxx'
  };
  console.log(Object.create(obj)); */
</script>

<script>
  /* ES6中的类和继承 */
  class Parent {
    constructor() {
      this.x = 100;
    }
    // Parent.prototype.get X = function... ,在Parent.prototype上添加方法getX
    getX() {
      return this.x;
    }
  }

  // 继承: extends Parent(类似于寄生组合继承)
  // 注意:继承后,【如果子类有constructor,】一定要在constructor第一行加上super
  class Child extends Parent {
    constructor() {
      // 类似于我们之前的CALL继承。super(100,200):相当于把Parent中的constructor执行,传递了100和200
      super();
      this.y = 200;
    }
    getY() {
      return this.y;
    }
  }

  let c1 = new Child;
  console.log(c1);
  
  // Child(); // => Uncaught TypeError: Class constructor Child cannot be invoked without 'new' : ES6中创建的就是类,不能当做普通函数执行,只能new执行
</script>

// 补充案例
function wjl(name, age) {
  // name、age通过参数传进来的,是每一个实例对象私有的属性。
  // height、house不是通过参数传进来的,是所有实例对象共有的属性。
  this.name = name
  this.age = age
  this.height = 188
  this.house = function () {
    return '兰博基尼'
  }
}

wjl.prototype.money = 888
var obj = new wjl('王健林', 12) // obj是wjl的实例对象, 参数 '王健林'、12是obj这个实例对象私有的,不是wjl所有的实例对象共有,这里的 '王健林'、12 和 wsc的实例对象o 没有关系
console.log('obj-------', obj) // wjl {name: "王健林", age: 12, height: 188, house: ƒ}

function wsc(names, ages) {
  this.names = names
  this.ages = ages
  wjl.call(this) // 继承wjl,而不是wjl的实例
}

var o = new wsc('王思聪', 22, 33, 55)
console.log('o----', o) // wsc {names: "王思聪", ages: 22, name: undefined, age: undefined, height: 188, …}

// 【'王健林'、12是obj实例的私有属性,不是wjl类的所有实例继承的属性。如果在wjl类中写 this.height = 188,而不是传进来的参数,那么this.height = 188就是wjl类的所有实例继承的属性、属性值,就像wjl类的this.house。】
console.log(o.house, o.name, o.age) // 函数 undefined undefined  
console.log(o.house, o.names, o.ages) // 函数 王思聪 22
原文地址:https://www.cnblogs.com/jianjie/p/13215735.html