1.背景介绍
继承,指一个对象间接应用另一对象的属性和办法。
JS里罕用的有如下两种继承形式:
原型链继承(对象间的继承)
类式继承(构造函数间的继承)
2.常识分析
JavaScript语言的对象体系,不是基于“类”,而是基于构造函数(constructor)和原型(prototype)。
- 原型对象:只有创立一个新函数,就会依据特定的规定为该函数创立一个prototype属性指向其原型对象,默认状况下原型对象会主动取得一个constructor属性,该属性蕴含一个指向prototype属性所在函数的指针。
Function.prototype.constructor === Function //true
- 构造函数:自身是一个函数,出于创立特定类型新对象的目标而定义的,外部应用this变量,须要和new配合应用来创立实例,this变量会绑定在实例对象上。
demo:
var f = function(){} f.prototype.constructor === f //true
1 原型链继承
function Box() { this.name = "lee"; } function Desk() { this.age = 100; } Desk.prototype.age = 200; function Table() { this.level = "aaaa"; } Desk.prototype = new Box(); //Desk继承了Box Table.prototype = new Desk(); //Table继承了Desk和Box var desk = new Desk(); alert(desk.name); //lee var table = new Table(); alert(table.name); //lee //如果要实例化table,那么Desk实例中有age=100,原型中减少雷同的属性age=200,最初后果是多少呢? alert(table.age); //100,还是就近准则 //毛病:无奈传参,援用共享,解决办法:对象假冒
2 经典继承:借用构造函数或称为对象假冒继承
var desk = new Desk(200); alert(desk.age); //200 alert(desk.name); //lee,jack,hello desk.name.push("AAA"); alert(desk.name); //lee,jack,hello,AAA var desk2 = new Desk(300); alert(desk2.name); //lee,jack,hello //毛病:借用构造函数尽管解决了方才两种问题,但没有原型,复用则无从谈起。
3 组合继承:原型链+借用构造函数。
调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用
//组合式继承是JavaScript最罕用的继承模式;但,组合式继承也有一点小问题,就是超类型在应用过程中会被调用两次:一次是创立子类型的时候,另一次是在子类型构造函数的外部。寄生继承将解决这个问题 function Box(age) { this.name = ['Lee', 'Jack', 'Hello'] this.age = age; } Box.prototype.run = function () { return this.name + this.age; }; function Desk(age) { Box.call(this, age); //对象假冒 , 第二次调用Box } Desk.prototype = new Box(); //原型链继承 var desk = new Desk(100); //第一次调用Box alert(desk.run());
4 原型式继承:这种继承借助原型并基于已有的对象创立新对象,同时还不用因而创立自定义类型。
function obj(o) { //传递一个字面量函数 function F() { } //创立一个构造函数 F.prototype = o; //吧字面量函数赋值给构造函数原型 return new F(); //最终返回出实例化的构造函数 } var box = { //字面量对象 name: "lee", arr: ['gege', 'meimei', 'jiejie'] } var box1 = obj(box); alert(box1.name); box1.name = "jack"; alert(box1.name); alert(box1.arr); box1.arr.push("父母"); alert(box1.arr); var box2 = obj(box); alert(box2.name); alert(box2.arr); //援用类型共享了
5 寄生式继承:原型式+工厂模式,目标是封装创建对象过程
function obj(o) { function F() { } F.prototype = o; return new F(); } function create(box, desk) { var f = obj(box.prototype); f.constructor = desk; desk.prototype = f; } function Box(name) { this.name = name; this.arr = ['哥哥', '妹妹', '父母']; } Box.prototype.run = function () { return this.name; }; function Desk(name, age) { Box.call(this, name); this.age = age; } inPrototype(Box, Desk); //通过这里实现继承 var desk = new Desk('Lee', 100); desk.arr.push('姐姐'); alert(desk.arr); alert(desk.run()); //只共享了办法 var desk2 = new Desk('Jack', 200); alert(desk2.arr); //援用问题解决
6.es6继承
代码量少,易懂
//class 相当于es5中构造函数//class中定义方法时,前后不能加function,全副定义在class的protopyte属性中//class中定义的所有办法是不可枚举的//class中只能定义方法,不能定义对象,变量等//class和办法内默认都是严格模式//es5中constructor为隐式属性class People{ constructor(name='wang',age='27'){ this.name = name; this.age = age; } eat(){ console.log(`${this.name} ${this.age} eat food`) }}//继承父类class Woman extends People{ constructor(name = 'ren',age = '27'){ //继承父类属性 super(name, age); } eat(){ //继承父类办法 super.eat() } } let wonmanObj=new Woman('xiaoxiami'); wonmanObj.eat();
ES5继承和ES6继承的区别
es5继承首先是在子类中创立本人的this指向,最初将办法增加到this中Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
es6继承是应用关键字先创立父类的实例对象this,最初在子类class中批改this