javascript继承,ES5继承,ES6 class extends关键字的继承

756 阅读2分钟

js中的继承

  1. 构造函数 call(第一次调用父类构造函数)
  2. 原型链 子类原型 = 父类实例(第二次调用父类构造函数) 子类构造函数要指回自己
  3. 组合(1+2) 缺点:调用两次父类构造函数,性能浪费
  4. 原型 Object.create() 对父类prototype的浅复制
  5. 寄生(4的增强) 做constructor的指回
  6. 寄生组合(1+5) 无性能问题的完美继承方式
  7. ES6 class extends关键字的继承 与寄生组合一样,有一些 细节上的不同

这里从Object.create这个函数开始说起 内部实现为:

//原型继承
function object(o){
	function F(){}
    F.prototype = o
    return new F()
}

//对原型继承进行增强的寄生继承
function createAnother(o){
	var clone = object(o)
    clone.say = function{    //以某种方式增强这个对象
    	console.log('Hi')
    }
    return clone
}
//ES5寄生组合实现自己的extends
function myExtends(SuperType,SubType){
	var prototype = Object.create(SuperType.prototype)  //实现了父类原型的浅复制
	prototype.constructor = SubType       //修正构造函数指向
	SubType.prototype = prototype        
}


function Super1(name){
	this.name = name
}

Super1.prototype.say = function(){
	console.log('hi')
}


function Sub1(name,age){
	Supertype.call(this,name)
	this.age = age
}

//核心:因为是对父类原型的浅复制,不包含父类的构造函数,所以不会调用两次父类的构造函数造成浪费
myExtends(Super1,Sub1)

Sub1.prototype.say() //hi

//完美继承

setPrototypeOf(A,B)方法

相当于 A.__proto__ = B

Object.setPrototypeOf = function(obj,proto){
	obj.__proto__ = ptoto
    return obj
}

getPrototypeOf(A)方法

得到A的__proto__

ES5和ES6继承的异同

ES5:寄生组合继承 使用Object.create(),父类构造函数的复制,没有原型链指向 先创建子类实例this对象,再对其增强 ES6:extends关键字 子类构造函数的原型链指向父类的构造函数 先将父类实例对象的属性和方法加到this上面,再用子类构造函数修改this,所以必须先调用super方法

//ES6 extends 继承
function _extends(SuperClass,SubClass){
	//这里可以写成 Object.setPrototypeOf(SubClass.prototype,SuperClass.prototype)
	SubClass.prototype.__proto__ = SuperClass.prototype //Sub的实例继承Super的实例
    SubClass.prototype.constructor = SubClass
    SubClass.__proto__ = SuperClass   //Sub继承Super的静态属性
}

function SuperClass(name){
	this.name = name
}

function SubClass(name,age){
	_extends(SuperClass,SubClass)  //将Sub的原型指向Super
    SuperClass.call(this,name)     //相当于super关键字
    //也可以写成 Object.getPrototypeOf(SubClass)   //==SuperClass
    
    this.age = age
    return this
}