我们在上一节的时候探讨过面向对象的封装,和别的面向语言相比,js并没有class(类)的概念,那么我就要实现类的概念要怎么操作呢?今天就来说说js的几种继承。
一、何为继承
继承时一种在新对象上复用现有对象的属性的形式,是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,这有助于复用代码和重复数据。
二、继承的方法
首先,我们先创建一个构造函数作为父类:
function Vip(){
this.type = 'VIP'
}
Vip.prototype.money = 6666;
我们再创建一个构造行数
function User(name, age){
this.name = name;
this.age = age;
}
我们现在想让User继承vip的属性/方法,要怎么继承呢?
1 )、原型链继承 让父类的实例作为子类的原型
User.prototype = new Vip();
console.log(User.prototype.constructor) //VIP
User.prototype.constructor = User;
var zhang = new User('张三',29)
你会发现中间有一段User.prototype.constructor = User,我们上一节有说过,任何一个prototype对象都有一个constructor属性指向它的构造函数,任何一个实例constructor属性也指向创建它的构造函数。 所以根据上面的console你会发现通过User.prototype = new Vip()后指针会发生变化,这个时候我们就要帮它重新定义;
这个就是我们说的原型链继承了,它的优缺点也显而易见:
优点:
1、父类新增原型方法/原型属性,子类都能访问到
2、容易实现,不复杂
3、即继承父类也继承子类
缺点:
1、来自原型对象的所有属性被所有实例共享,如果实例更改原型对象上的引用类型的话,所有实例都会受到影响;(值类型成员不会更改,子类型成员会发生更改)
2、创建子类实例时,无法向父类构造函数传参
2 )、构造函数继承 使用call或apply方法,把父类的构造函数赋值给子类
我们直接改写User构造函数
function User(name, age){
Vip.call(this,arguments);
this.name = name;
this.age = age;
}
var zhang = new User('张三',29);
优点:
1、只是继承子类,没有继承父类;
2、没有涉及父类的原型,只能引用父类函数的方法;
3、能够向父类函数传参数;
4、解决了第一种方式缺点1,子类实例共享父类引用属性的问题;
缺点:
1、只能继承父类的实例属性和方法,不能继承父类的原型属性/方法
2、实例并不是父类的实例,只是子类的实例
3 ) 、实例继承 为父类实例添加新特性,作为子类实例返回
function User(name, age){
var list = new Vip();
list.name = name;
list.age = age;
return list;
}
var zhang = new User('张三', 29);
4 ) 拷贝继承 把父对象的所有属性和方法,拷贝进子对象, 实现继承
function User(name, age){
var list = new Vip();
for(var p in animal){
User.prototype[p] = list[p];
}
}
var zhang = new User('张三', 29);
特点:
1、支持多继承
2、可以传参
缺点:
1、效率较低,内存占用高(因为要拷贝父类的属性)
2、无法获取父类不可枚举的方法(不能使用for in 访问到)
5) 组合继承 通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用(原型链继承+构造函数继承)
function User(name, age){
Vip.call(this);
}
User.prototype = new Vip.();
User.prototype.constructor = User;
优势:
1、拥有原型链继承和构造函数继承的优点
缺点:
1、调用了两次父类构造函数,消耗了一些内存;
6) 寄生组合继承 相对于组合继承,通过第三对象继承父类的原型的方式,去掉继承父类实例属性,也避免了两次调用父类构造函数
function User(name, age){
Vip.call(this);
}
var Demo= function(){};
Demo.prototype = Vip.prototype;
User.prototype = new Demo();
User.prototype.constructor = User;
var zhang = new User('张三', 29);
优点:
1、解决以上方法所有的缺点;
缺点:
1、实现起来较为复杂
以上的方法有参考网络上的一些文章,如果你对以上的方法以及逻辑不是特别明白的话,欢迎留意或者查看以下文章, 会对你了解继承的方法很有用的: