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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。