JavaScript继承

139 阅读2分钟
  • 原型链继承

​ 原型链继承存在的问题:

​ 问题1:原型中包含的引用类型属性将被所有实例共享;

​ 问题2:子类在实例化的时候不能给父类构造函数传参;

function Animal() {
    this.colors = ['black', 'white']
}
Animal.prototype.getColor = function() {
    return this.colors
}
function Dog() {}
Dog.prototype =  new Animal()

let dog1 = new Dog()
dog1.colors.push('brown')
let dog2 = new Dog()
console.log(dog2.colors)  // ['black', 'white', 'brown']
  • 借用构造函数实现继承

    借用构造函数实现继承解决了原型链继承的 2 个问题:引用类型共享问题以及传参问题。但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法

function Animal(name) {
    this.name = name
    this.getName = function() {
        return this.name
    }
}
function Dog(name) {
    Animal.call(this, name)
}
Dog.prototype =  new Animal()
  • 组合继承

    组合继承结合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是==使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性==。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。

function Animal(name) {
    this.name = name
    this.colors = ['black', 'white']
}
Animal.prototype.getName = function() {
    return this.name
}
function Dog(name, age) {
    Animal.call(this, name)
    this.age = age
}
Dog.prototype =  new Animal()
Dog.prototype.constructor = Dog

let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2) 
// { name: "哈赤", colors: ["black", "white"], age: 1 }
  • 圣杯模式继承

    组合继承已经相对完善了,但还是存在问题,它的问题就是调用了 2 次父类构造函数,第一次是在 new Animal(),第二次是在 Animal.call() 这里。

    所以解决方案就是不直接调用父类构造函数给子类原型赋值,而是通过创建空函数 F 获取父类原型的副本。

// 1.第一种
function inherit(target, origin) {
    function F(){}
    F.prototype = origin.prototype
    target.prototype = new F()
    target.prototype.consctruct = target
    target.prototype.Uber = origin.prototype
}
// 重写第一种写法
var inherit = (function(){
    var F = function(){}
    return function(target, origin){
        F.prototype = origin.prototype
        target.prototype = new F()
        target.prototype.consctruct = target
        target.prototype.Uber = origin.prototype
    }
}())

  • class继承
class Animal {
    constructor(name) {
        this.name = name
    } 
    getName() {
        return this.name
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name)
        this.age = age
    }
}