开始之前,我们需要先知道:
- 每个对象都有一个__proto__内部属性指向它的构造函数的原型对象,每个函数都有一个prototype属性指向它的原型对象。而每一个函数都是对象,所以一个函数既有__proto__内部属性,又有prototype属性。
- 每一个实例,都有一个内部属性__proto__指向它的构造函数的原型对象。
还需要再说一下。__proto__与prototype是不一样的。区别如下
- | __proto__ | prototype |
---|---|---|
存在性 | __proto__是每个对象都有的(包括函数) | 只有函数才有 |
含义 | __proto__是指向它的构造函数的原型对象 | 指向函数的原型对象 |
?
上面可能有些不好理解
解释
现在开始啦!
/*用es6的extends实现的继承*/
class Point1 {
}
class ColorPoint1 extends Point1 {
}
/*用es5中原型链实现的继承*/
function Point2(){
}
let p=new Point2();
function ColorPoint2(){}
ColorPoint2.prototype=p;
在es5中,基础是通过修改子类构造方法的原型对象实现的,也就是ColorPoint2.prototype=p
,而在es6中,直接用extends
就行了。下面看一下区别。
ColorPoint1.__proto__ === Point1
//true
ColorPoint2.__proto__===Point2
//false
ColorPoint1.prototype.__proto__ === Point1.prototype
//true
ColorPoint2.prototype.__proto__ === Point2.prototype
//true
区别从上面代码中可以看出。就是ColorPoint2.proto===Point2
与ColorPoint2.prototype.proto === Point2.prototype
的区别。
这是为什么呢?是因为es6类的继承是用下面方式实现的。
class A {
}
class B {
}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);
const b = new B();
注意,setPrototypeOf
设置一个对象内部属性__proto__
为另外一个对象。如Object.setPrototypeOf(B, A)
就是设置B.__proto__ = A。
接下来,我们看一下es6中继承的原型链图,如图1所示。
图中,蓝线就是Object.setPrototypeOf(ColorPoint1, Point1)
而es5中,用原型链实现的继承的示意图如图2所示。
在es5用原型链实现继承的示意图中,子类构造函数的__proto__是没有进行处理的,还是指向了Object.__proto__。
总结
es6使用extends实现继承与es5使用原型链实现继承区别在于,es6设置了构造函数的继承,也就是子类构造函数的proto为父类构造函数。具体代码就是下面。
// ColorPoint1.prototype的proto继承Point1.prototype
Object.setPrototypeOf(ColorPoint1.prototype, Point1.prototype);
// ColorPoint1的proto继承point。
Object.setPrototypeOf(ColorPoint1, Point1);