这几天在学习react的时候学习到ES6的 class extends 继承方式,就复习一下ES5的继承机制,并整理下来。python
- ES5继承机制
- ES6继承机制
- 二者的区别总结
在js万物皆对象,但事仍是区分普通对象和函数对象,那你们须要知道是只有函数对象才有prototype属性,但全部对象都有__proto__属性react
function A(){
}
var B = new A;
复制代码
那这里就得出几个公式:es6
B.__proto__== A.prototype;
B.constructor == A;
a.prototype.constuctor = A;
复制代码
那这是实现继承的基础; 也就是说A.prototype是A的原型对象,A是构造函数,B是A的实例,原型对象(A.prototype)是 构造函数(A)的一个实例。而此时this指向是指向实例。 明白这个关系实现继承就很简单了!看一下下面的代码app
经过重写子类的原型 等于 父类的一个实例,(父类的实例属相变成子类的原型属性)函数
function father() {
this.faName = 'father';
}
father.prototype.getfaName = function() {
console.log(this.faName);
};
function child() {
this.chName = 'child';
}
child.prototype = new father();
child.prototype.constructor = child;
child.prototype.getchName = function() {
console.log(this.chName);
};
复制代码
经过子类的原型对象指向父类实例的方式来实现继承,那咱们不难发现原型链的造成是真正是靠__proto_ 而非prototype,子类的实例能够访问父类原型上的方法,是由于子类实例经过 _proto 与父类的原型对象有链接工具
//先来个父类,带些属性
function Super(){
this.flag = true;
}
//为了提升复用性,方法绑定在父类原型属性上
Super.prototype.getFlag = function(){
return this.flag;
}
//来个子类
function Sub(){
this.subFlag = false;
}
//实现继承
Sub.prototype = new Super;
//给子类添加子类特有的方法,注意顺序要在继承以后
Sub.prototype.getSubFlag = function(){
return this.subFlag;
}
//构造实例
var es5 = new Sub;
复制代码
所谓寄生组合式继承,即经过借助构造函数来继承属性,经过原型链的混成形式来继承方法。 其背后的基本思路是:没必要为了指定子类型的原型而调用超类型的构造函数,咱们所须要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,而后再将结果指定给子类型的原型。学习
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
复制代码
ES5的继承机制简单来讲就是:实质是先创造子类的实例对象this,而后再将父类的方法添加到this上面(Parent.apply(this))this
class Point {
constructor(x) {
this.x = 1;
this.p = 2;
}
print() {
return this.x;
}
}
Point.prototype.z = '4'
class ColorPoint extends Point {
constructor(x) {
this.color = color; // ReferenceError
super(x, y);
this.x = x; // 正确
}
m() {
super.print();
}
}
复制代码
ES6继承是经过class丶extends 关键字来实现继承 Point是父类,ColorPoint 是子类 经过 class 新建子类 extends继承父类的方式实现继承,方式比ES5简单的多。es5
constructor 方法是类的构造函数,是一个默认方法,经过 new 命令建立对象实例时,自动调用该方法。一个类必须有 constructor 方法,若是没有显式定义,一个默认的 consructor 方法会被默认添加。因此即便你没有添加构造函数,也是会有一个默认的构造函数的。通常 constructor 方法返回实例对象 this ,可是也能够指定 constructor 方法返回一个全新的对象,让返回的实例对象不是该类的实例。spa
class Points {
constructor(x) {
this.x = 1;
this.p = 2;
}
print() {
return this.x;
}
statc getname(){
return new.target.name;
}
}
等同于:
function Points(x) {
this.x = x;
this.p = 2;
}
Points.prototype.print = function() {
return '(' + this.x +')';
}
复制代码
也就是说constructor就表明在父类上加属性,而在class对象加方法属性 等于在原型上的加。而这些属性方法 只有经过new出的实例 或者是extends 继承出来的实例才能够获取到 因此咱们能够获得
new Points().__proto__.print() //能够调用到Points的print方法
new Points().x = 1 //能够调用到constructor 里面的 this.x=1
复制代码
super既能够当作函数使用,也能够当作对象使用两种使用的时候彻底不同, 函数用时 : 在 constructor 中必须调用 super 方法,由于子类没有本身的 this 对象,而是继承父类的 this 对象,而后对其进行加工,而 super 就表明了父类的构造函数。super 虽然表明了父类 A 的构造函数,可是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,所以 super() 在这里至关于
A.prototype.constructor.call(this, props)
复制代码
在 super() 执行时,它指向的是 子类 B 的构造函数,而不是父类 A 的构造函数。也就是说,super() 内部的 this 指向的是 B。因此在第一个es6的例子中子类的this指向的是本身。、
当作对象使用 : 在普通方法中,指向父类的原型对象;在静态方法中,指向父类。 因此在子类的方法中super.print();指向的是父类原型上的方法。 可是由于super的两种用法,因此es6规定在使用必需要明确使用方式,像单独console.log(super) 就会报错。
顾名思义是静态方法的意思,类至关于实例的原型, 全部在类中定义的方法, 都会被实例继承。 若是在一个方法前, 加上static关键字, 就表示该方法不会被实例继承, 而是直接经过类来调用, 这就称为“ 静态方法”。静态方法调用直接在类上进行,而在类的实例上不可被调用。静态方法一般用于建立 实用/工具 函数。
new.target属性容许你检测函数或构造方法是否经过是经过new运算符被调用的。在经过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是undefined。
也就是说new.target的功能就是用来检测函数的调用是否是经过 new 去建立一个新对象的,并且new.target返回的是一个指向函数的引用,也就是说咱们可以肯定是哪一个函数进行了new操做。
先建立父类实例this 经过class丶extends丶super关键字定义子类,并改变this指向,super自己是指向父类的构造函数但作函数调用后返回的是子类的实例,实际上作了父类.prototype.constructor.call(this),作对象调用时指向父类.prototype,从而实现继承。