JavaScript继承

以下栗子都会使用一个公共的父类

// 创建一个父类
    function Animal(name) {
        this.name = name || 'Animal';
        this.sleep = function() {
            console.log(this.name + ' 正在睡觉')
        }
    }

    Animal.prototype.eat = function(food) {
        console.log(this.name + ' 正在吃 ' + food);
    }

1. 基于原型链的继承

将上级函数的实例赋值给下级函数的原型

// 新建一个Cat类
function Cat(lname) {
    this.lname = lname
    this.say = function() {
        console.log('喵~')
    }
}

// 将上级函数的实例复制给下级函数的原型prototype
Cat.prototype = new Animal()
// 但是要想给子类的原型新增方法,需要在new Animal()语句之后进行
Cat.prototype.cname = 'sigoudaner' 

// 新建一个cat类
let cat = new Cat('goudaner', '小明')

console.group()
console.log(cat.name, '---cat.name')
console.log(cat.lname, '---cat.lname')
console.log(cat.cname, '---cat.cname')
cat.say()
cat.sleep()
cat.eat('yu')
console.log(cat instanceof Animal) // true
console.log(cat instanceof Cat) // true
JavaScript继承_第1张图片
image.png
  • 优点
    肥肠纯粹的继承关系,实例是子类的实例,也是父类的实例
    父类新增的原型实行方法,子类都可以访问到
    简单
  • 缺点
    可以在构造器中给子类新增属性和方法,但是要想给子类的原型扩展属性和方法必须要在new XXX(赋值语句之后,不然会给覆盖)
    无法实现多继承
    创建子类实例时,无法向父类构造函数传参
    来自原型对象的引用属性是所有实例共享的

构造继承

使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

// 构造继承
function Cat(name) {
    Animal.call(this);
    this.name = name || 'goudaner'
}
let cat = new Cat()

console.group()
console.log(cat.name)
cat.sleep()
console.log(cat instanceof Animal)
console.log(cat instanceof Cat)
cat.eat('鱼')
JavaScript继承_第2张图片
image.png
  • 优点
    子类不共享父类引用属性
    创建子类时可以向父类传递参数
    可以实现多继承(call多个父类对象)
  • 缺点
    实例并不是父类的实例,只是子类的实例
    只能继承父类的属性和方法,不能继承父类原型属性和方法
    不能实现函数复用,每个子类都有父类实例函数的副本,影响性能

实例继承

为父类实例添加新特性,作为子类实例返回

function Cat(name){
    var _Cat = new Animal();
    _Cat.name = name || 'goudaner';
    _Cat.lname = 'sigoudaner';
    return _Cat; // 将父类的实例添加新特性之后,作为子类的实例返回
}

// 声明实例可以有两种方式
let cat = new Cat()
let cat = Cat()

console.group()
console.log(cat.name)
console.log(cat.lname)
cat.sleep()
cat.eat('鱼')
console.log(cat instanceof Animal) // true
console.log(cat instanceof Cat) // false
  • 优点
    不限制调用方式
  • 缺点
    实例是父类的实例,不是子类的实例
    不支持多继承

组合继承

将原型链继承和构造继承组合使用

function Cat(name){
    Animal.call(this);
    this.name = name || 'goudaner';
}
// 比构造继承就多了下面这句话
Cat.prototype = new Animal();

var cat = new Cat();

console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
  • 优点
    集成了原型链继承和构造继承的优点
  • 缺点
    调用了两次父类构造器,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
    但是,仅仅是多消耗了一点内存;

es6实现继承

相对于继承更加友好

class Cat extends Animal {
    constructor(name) {
        super()
        this.name = name
    }
    say() {
        console.log('喵~')
    }
}

let cat = new Cat('goudaner')

console.group()
console.log(cat.name)
cat.sleep()
cat.eat('鱼')
cat.say()
console.log(cat instanceof Animal)
console.log(cat instanceof Cat)
JavaScript继承_第3张图片
image.png
  • 优点
    相对于之前来说更加友好

关于原理请点击详情

你可能感兴趣的:(JavaScript继承)