Javascript中的继承

97 阅读2分钟

原型和原型链

每个实例对象都有属性__proto__,指向其构造函数的特殊对象prototype。特殊对象prototype即为原型。当查找实例对象的属性或方法时:

  • 先从其本身上查找

  • 如果没有则从对象的__proto__指向的prototype上查找

  • 如果该prototype上仍没有,则查找其__proto__指向的prototype,直到找到或__proto__指向的为null

__proto__指向的为null时即查找到了Object.prototype上

new操作符

const instance = new Constructor(props)
let instance = {}
instance.setPrototypeConstructor.prototype// obj.__proto__ = Constructor.prototype
const res = Constructor.call(instance, props)
instance = res instanceOf Object ? res : instance

上述两段代码等价,即说明了new创建实例对象的四个步骤:

  • 创建空对象instance
  • instance__proto__指向构造函数的prototype
  • 调用构造函数并将其this指向instance
  • 如果构造函数返回的值为对象,则将instance赋值为该对象
  • new创建实例的结果即为instance

ES5继承

09年12月ES5发布,15年6月ES6发布,15年后的ECMAScript统称为ES6

function SuperClass(props) {
    this.props = props
}
SuperClass.method1 = function() {
    return 'method1'
}
SuperClass.prototype.superMethod = function() {
    return this.props
}
function SubClass(subProps, superProps) {
    this.subProps = subProps
    SuperClass.call(this, superProps)
}
Object.setPrototypeOf(SubClass.prototype, SuperClass.prototype)
// 继承 method1 这种写法的方法和属性,等同于静态方法和静态属性
Object.setPrototypeOf(SubClass, SuperClass)
SubClass.prototype.subMethod = function() {
    return this.subProps
}
const subInstance = new SubClass(subProps, superProps)

继承的目的为代码和逻辑的复用。不同于其他语言中的继承,js实现代码复用的方式为借用父类的构造函数和将子类prototype对象的__proto__指向父类的prototype

ES6继承

class SuperClass {
    // 静态属性 和 静态方法也会被继承
    static staticProp = 'staic prop'
    static staticMethod() {
        return 'static method'
    }
    // 私有属性 和 私有方法不会被继承
    #privateProp = 'private prop'
    #privateMethod() {
        return 'private method'
    }
    constructor(props) {
        // 虚基类
        if(new.target === SuperClass) {
            throw new Error('该类不能被实例化')
        }
        this.props = props
    }
    superMethod() {
        return this.props
    }
}
class SubClass extends SuperClass {
    // 静态属性,静态方法
    static count = 0
    static inc() {
        this.count++
    }
    // 私有属性,私有方法
    #privateProperty = 'private' 
    #privateMethod() {
       return 'private method' 
    }
    // 构造函数
    constructor(superProps, subProps) {
        SubClass.inc()
        super(superProps) // 调用super后才能使用this
        this.subProps = subProps
    }
    subMethod() {
        return this.subProps
    }
    // getter
    get props() {
        return this.subProps
    }
    // setter
    set props(val) {
        this.subProps = val
    }
}

super在类内可以

ES6中的类的内部所有定义的方法,都是不可枚举的

ES6继承是ES5的语法糖