一起手写吧!ES5和ES6的继承机制!

原型

执行代码var o = new Object();

此时o对象内部会存储一个指针,这个指针指向了Object.prototype,当执行o.toString()等方法(或访问其他属性)时,o会首先查看自身有没有该方法或属性,如果没有的话就沿着内部存储的指针找到Object.prototype对象,然后查看Object.prototype对象是否有对应名称的方法或属性,如果有就调用Object.prototype的方法或属性。

我们把这个指针叫做o对象的原型。

ES3规范中定义了Object.prototype.isPrototypeOf()方法,该方法可以判断某个对象是不是另一个对象的原型。Object.prototype.isPrototypeOf(o)返回true值可以确定Object.prototype就是o对象的原型。

在ES3规范中,不能直接读取o对象的原型,也就是o对象的原型看不见摸不着的。ES5.1规范定义了Object.getPrototypeOf()方法,通过该方法可以获取对象的原型。我们可以通过Object.getPrototypeOf(o) === Object.prototype再次验证Object.prototype就是o对象的原型。

ES6规范更加直接,为对象添加了一个__proto__属性,通过这个属性就可以获得对象的原型,所以在支持__proto__的浏览器中,o.__proto__ === Object.prototype也会返回true。

当我们执行var x = new X();时,浏览器会执行x.__proto__ = X.prototype,会将实例化对象的原型设置为对应的类的prototype对象,这一点很重要。

原型链 

我们执行如下代码:

function Person(){};
var p = new Person();

p.__proto__指向了Person.prototype,Person.prototype的原型是Person.prototype.__proto__,其指向了Object.prototype,Object.prototype.__proto__为null。

通过__proto__向上追踪形成了如下的链式结构:

p -> Person.prototype -> Object.prototype -> null

这一原型的链式结构就叫做原型链。Object.prototype的原型是null,也就是说Object.prototype没有原型。

JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

JavaScript中的继承是通过原型实现的,虽然在ES6中引入了class关键字,但是它只是原型的语法糖,JavaScript继承仍然是基于原型实现的。 

 

ES5寄生组合继承 (业内比较提倡的方法)

即通过借助构造函数来继承属性,通过原型链的混成形式来继承方法。
其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function inserit(son, father) {
    var obj = Object.create(father.prototype);
    son.prototype = obj;
    obj.constructor = son
}

function SuperType(name, colors) {
    this.name = name;
    this.colors = colors;
}
SuperType.prototype.sayName = function () {
    return this.name;
}

function SubType(job, name, color) {
    SuperType.call(this, name, color);
    this.job = job;
}
//核心方法
inserit(SubType, SuperType);
SubType.prototype.sayjob = function () {
    return this.job;
}
var instance = new SubType("doctor", "John", ["red", "green"]);
console.log(instance.sayjob(), instance.sayName()) //doctor,John

ES6继承

ES6支持通过类来实现继承,方法比较简单,代码如下

class Point {
    constructor(x, y) {
        this.x = x
        this.y = y
    }
    
    toString() {
        return this.x + '' + this.y
    }
}

class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y) //调用父类的constructor(x, y)
        this.color = color
    }
    
    toString() {
        return this.color + ' ' + super.toString() // 调用父类的toString()
    }
}

var colorPoint = new ColorPoint('1', '2', 'red')

console.log(colorPoint.toString())  // red 12

 

posted @ 2020-04-20 00:03  Magi黄元  阅读(783)  评论(0编辑  收藏  举报