JavaScript继承(class继承,原型,拷贝,寄生组合)

46 阅读2分钟

函数的属性直接写在函数里面,函数的方法则写在函数的原型里面,具体看下面这段代码。

function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}
Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}

class写下面这段代码可以得到上面一样的效果,可以看成一个语法糖,只是把属性写在constructor里面。

class Person {
    constructor(name, age) {
        this.type = 'human'
        this.name = name
        this.age = age
    }
    sayName() {
        console.log('hello ' + this.name)
    }
}

用class写的话可以用extends实现继承,让子类继承父类的属性和方法,但是子类必须在constructor()方法中调用super(),如果不调用super(),子类就找不到自己的this,会发生报错。

class sun extends Person {
    constructor(name, age) {
        //继承父亲的属性
        super()
        //继承父亲的方法
        sayName() {
            super.sayName()
    }}
}

除开classextends实现继承,下面还有三种方法实现继承。

原型继承

function Student (name, age) {
  Person.call(this, name, age)
}
// 子类的原型指向了父类的实例,这样会调用两次父类构造函数
Student.prototype = new Person()
// 下面这个直接指向了父类的原型,会导致子类的constructor是父类的constructor
// Student.prototype = Person.prototype
var s1 = new Student('张三', 18)
// 这里可以访问到父类实例上的type属性,这是错误的
console.log(s1.type) // human
s1.sayName() // hello 张三

Person.call()实现让Student调用Person函数,然后把Student的原型指向Person的实例,这样会调用两次父类构造函数,不能直接把Student的原型指向Person的原型,这样会导致Student的constructor是Person的constructor.

拷贝继承

function Student (name, age) {
  Person.call(this, name, age)
}
// 这里拷贝父类原型上的属性和方法
for (var key in Person.prototype) {
    Student.prototype[key] = Person.prototype[key]
}
var s1 = new Student('张三', 18)
s1.sayName() // hello 张三

直接通过for in遍历Person的原型,然后直接把遍历到的属性和方法赋给Student,这样就可以直接实现继承。

寄生组合继承

function Student (name, age) {
  Person.call(this, name, age)
}
Student.prototype = Object.create(Person.prototype)
// 让子类的构造器还是指向自己的构造函数
Student.prototype.constructor = Student
var s1 = new Student('张三', 18)
console.log(s1.type) // human
s1.sayName() // hello 张三

寄生组合继承可以算是引用类型继承的最佳方式了,父类方法可以复用,父类的引用属性不会被共享。