js简介(继承)

原型链

实例与Object原型对象之间的链条称为原型链

原型模式的访问机制(原型搜索机制)

  1. 读取实例对象的属性时,先从实例对象本身开始搜索。如果在实例中找到了这个属性,则返回该属性的值;
  2. 如果没有找到,则继续搜索实例的原型对象,如果在原型对象中找到了这个属性,则返回该属性的值
  3. 如果还是没找到,则向原型对象的原型对象查找,依此类推,直到Object的原型对象(最顶层对象);
  4. 如果再Object的原型对象中还搜索不到,则抛出错误;
演示:画图讲解原型链继承

继承

继承是面向对象中一个非常重要的特征。指的是:子类继承父类的属性和方法。

我们可以通过继承的方式, 在父类的属性和方法基础上, 让子类也拥有这些属性和方法, 并可以扩展。

继承的好处:

  1. 子类拥有父类所有的属性和方法(代码复用);
  2. 子类可以扩展自己的属性和方法(更灵活);
  3. 子类可以重写父类的方法

继承方式

原型链继承

  • 核心:拿父类实例来充当子类原型对象
  • 缺点:
    • 无法操作父类构造函数的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype = {
say(){console.log(`大家好,我叫${this.name},欢迎跟大家交朋友`)}
}
Object.defineProperty(Person.prototype,'constructor',{
configurable:true,
value:Person
});
let lemon = new Person('lemon',32,'女');
//===============原型链继承==========
function Man(name,age){
}
Man.prototype = new Person();
let laoxie = new Man('laoxie',18);

借用构造函数

核心:借父类的构造函数来增强子类实例,相当于把父类的实例属性复制一份给子类实例

  • call:
    • 格式:父类构造函数.call(子类实例,参数1,参数2,参数3…)
  • apply:

    • 格式:父类构造函数.apply(子类实例,[参数1,参数2,参数3…])
      call与apply的唯一区别:传参方式不同,call多个参数,apply只有两个参数,第二个参数为数组

      1
      2
      3
      //aplly用法:借用方法
      var arr = [20,2,40,33,21,8,22,46,32]
      Math.max.apply(null,arr)

组合继承

由于以上继承方法的缺点,实际开发中不可能单纯的只使用一种继承方法,而是利用它们的优点,规避它们的缺点,所以就有了组合继承法

  • 继承属性:借用构造函数
    • 只在构造函数中定义属性
  • 继承方法:原型链继承
    • 把所有的方法写入原型对象

组合继承是最常用的继承模式。

  • 缺点(原型链继承法的缺点):
    • 在原型对象中生成多余的属性
    • 多次执行父类构造函数
1
2
3
4
//原型链继承基础上补充借用构造函数
function Man(name,age){
Person.call(this,name,age,'男');
}

原型式继承

  • 核心:先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例

  • 解决原型链继承法的缺点:生成多余的属性

    1
    2
    3
    4
    5
    6
    function object(o){
    function F(){}
    F.prototype = o;
    return new F();
    }
    Man.prototype = object(Person.prototype);

ES5版本的原型式继承:Object.create()

寄生组合继承法

完美的继承方法

  • 核心:
    • 继承属性:借用构造函数
    • 继承方法:原型式继承

ES6继承

Class定义类

  • 写在类里面的方法实际是给Person.prototype添加方法
  • constructor方法是类的默认方法,相当于在构造函数内生成属性

extends继承

  • 子类继承了父类,在子类构造函数中必须调用super方法。
  • 子类的constructor方法没有调用super之前,不能使用this关键字,否则报错,而放在super方法之后就是正确的。

静态方法

如果在一个方法前,加上static关键字,这就称为“静态方法”

  • 静态方法方法不会被实例继承,而是直接通过类来调用Person.getInfo()

  • 父类的静态方法,可以被子类继承Man.getInfo()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Person{
    constructor(name,age,gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
    }
    // 此处的方法写入原型对象中
    say(){console.log(大家好,我叫${this.name})};
    static eat(){console.log('我是吃货');}
    }
    let lemon = new Person('lemon',32,'女');
    // 继承方法
    class Man extends Person{
    constructor(name,age){
    // 继承属性
    super(name,age,'男');
    this.hobby = ['吃','喝'];
    }
    }
    let laoxie = new Man('laoxie',18);

call和apply的使用

1
2
3
4
5
6
7
* 求数组中最大数和最小数
* Math.max()
* Math.min()
* 类数组使用map
* 判断数据类型
* typeof
* Object.prototype.toString()