3.面向对象的三大特征中的 “继承” 和继承的几种方式

学习继承之前,要先了解什么是面向对象:(把相同的代码提取(抽象)出来归为一类,把公共的方法挂在 这个类的原型上 的一种编程思想(开发模式))

原型和原型链

面向对象的三大特征:抽象、封装、继承、(多态)

  • 抽象:提取类似的部分。
  • 封装:归类的过程。
  • 继承:子类拥有父类的属性或者方法,自己也有自己的一套属性和方法。

下面开始这篇随笔的主题:继承 和 继承的几种方式

注意:网上对继承的方式,描述都不一样,主要是起的名字不一样,但这不重要,从代码的原理上大致可以分成4种,我给他们起来我心中的名字

一. call继承(属性继承/类式继承)

一般我们把属性放在类里面,方法挂在原型上。
调用父类,通过 call 来改变 this(把 window 改成子类)
达到继承属性的目的。(无法继承 原型上的方法)

例子:
    function Person(name, age) {
      this.name = name;
      this.age = age;
    };
    Person.prototype.say = function() {
      return this.name + this.age
    }
    function Coder(name, age, job) {
      Person.call(this, name, age);
      this.job = job;
      // console.log(this);//Coder
    }
    let p = new Person('成龙', 58);
    let c = new Coder('房祖名', 26, '演员');

    console.log(c);//Coder {name: "房祖名", age: 26, job: "演员"}
    console.log(p);//Person {name: "成龙", age: 58}
    console.log(p.__propt__, c.__propt__) // 可以看到,无法继承原型上的方法。

二. 拷贝继承

原理:

  1. 用 for in 循环 Person.prototype,再复制给 Coder.prototype,这样Coder的实例 c 就可以使用 Person.prototype上的方法。
  2. 再结合 call 继承属性。
    此时就完成了 属性和方法 的继承。

注意:for in 会遍历整个原型链,(除了Person的原型,还会找Person的构造函数的原型。)为了保证只继承Person的方法,不包括 “祖先们” 的方法,此时需要用到 hasOwnproperty() 这个方法类判断一下

缺点:会遍历整个原型链,性能消耗大

    for (let attr in Person.prototype) {
      //必须保证赋值的数据是父级自身的属性
      if (Person.prototype.hasOwnProperty(attr)) {
        Coder.prototype[attr] = Person.prototype[attr];
      }
    }

三. 原型继承(有人叫寄生组合式继承)推荐指数 ❤❤❤❤❤

原理:

  1. 继承属性:用 call 继承的方式
  2. 继承方法:
炮灰.prototype = Person.prototype;
Coder.prototype = new 炮灰;
  1. 手动赋值一个 constructor 指向子类:
Coder.prototype.constructor = Coder;

很多可以继承的方法的核心原理就是这里提到的原型继承。比如 Object.create() / Object.assign() / Object.defineProperties() 。例子1过后,再简单介绍这些方法。

例子1:
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }

    Person.prototype.say = function () {
      console.log(this.name + ':呵呵');
    };

    function Coder(name, age) {
      Person.call(this, name, age);
    }//子类私有继承父类私有

    Coder.prototype = Object.create(Person.prototype);
    Coder.prototype.constructor = Coder;//子类公有继承父类共有

    let p = new Person('成龙', 68);
    let c = new Coder('房祖名', 29);

    /*    子类改变属性,不会影响父级
    c.name = 1
    console.log(c.name);//1
    console.log(p.name);//成龙  */

    c.say();//成龙:呵呵
    p.say()//房祖名:呵呵
例子2:

Object.create()
Coder.prototype = Object.create(Person.prototype); // 此时就完成了属性继承,注意:手动修改 constructor 的指向。
Object.create:内置Object类天生自带的方法
1. 创建一个空对象
2. 让新创建的空对象的__proto__指向第一个传递进来的对象

Object.assign():浅拷贝
Coder.prototype = Object.assign({},Person.prototype); // 类似拷贝
Object.assign(Coder.prototype, Person.prototype)
将多个对象的可枚举属性拷贝到目标对象上,并且返回赋值后的目标对象。
    Object.defineProperties():

Object.defineProperties()
给对象定义属性,如果存在该属性,
则用新定义的属性更新已存在的属性,
如果不存在该属性,则添加该属性。

四. ES6 继承 (逼格最高,也是未来的趋势,必学必用)

知识点:class 类,ES6给我们提供了class的语法糖,可以通过class来创建类

    class Person {//此行没有括号,在第二行constructor()传参
      constructor(name, age) { //constructor是一个构造方法,用来接收参数
        this.name = name;
        this.age = age;
      }
      /*下面的写法就等同于把方法挂在原型上*/
      static say() {// 加了static 静态方法,只给类用的方法
        console.log('哈哈');
      }//方法和方法之间不用加逗号 ,
      say() {//动态方法,给实例使用的方法
        console.log(this.name);
      }
    }

    let p = new Person('成龙', 20);
    p.say();//成龙

声明子类 extends 父类名 就继承父类了

    class Coder extends Person {
      /*
          在子类constructor中添加属性的小技巧

          专属于子类的属性写在参数的前面,父类的属性放在后面
          这样一来,就能直接使用...arg

          ...arg
              把函数中的多余的参数放入数组中体现出来。

      */
      constructor(job, ...arg) {
        // console.log(this)
        super(...arg); //等同于调用父类,把多余的参数(和父类一样的属性)放到super中,达到继承父类属性的目的
        /*
            在继承里,写constructor必须写super
            super下面才能使用this,super有暂存死区(super上面不能使用this,用了就报错)
        */
        this.job = job;//自己私有的属性,直接this点即可
        console.log(arg);
      }
      codeing() {
        console.log('敲代码');
      }
      say() {
        console.log('哈哈');
      }

    }

    let c = new Coder('前端', '周杰伦', 20);
    let p = new Person('张杰', 30);
    // delete c.name;
    console.log(c);
    // c.say();
    // p.say();
    // c.codeing();
posted @ 2018-11-05 09:36  真的想不出来  阅读(323)  评论(0编辑  收藏  举报