以下栗子都会使用一个公共的父类
// 创建一个父类
function Animal(name) {
this.name = name || 'Animal';
this.sleep = function() {
console.log(this.name + ' 正在睡觉')
}
}
Animal.prototype.eat = function(food) {
console.log(this.name + ' 正在吃 ' + food);
}
1. 基于原型链的继承
将上级函数的实例赋值给下级函数的原型
// 新建一个Cat类
function Cat(lname) {
this.lname = lname
this.say = function() {
console.log('喵~')
}
}
// 将上级函数的实例复制给下级函数的原型prototype
Cat.prototype = new Animal()
// 但是要想给子类的原型新增方法,需要在new Animal()语句之后进行
Cat.prototype.cname = 'sigoudaner'
// 新建一个cat类
let cat = new Cat('goudaner', '小明')
console.group()
console.log(cat.name, '---cat.name')
console.log(cat.lname, '---cat.lname')
console.log(cat.cname, '---cat.cname')
cat.say()
cat.sleep()
cat.eat('yu')
console.log(cat instanceof Animal) // true
console.log(cat instanceof Cat) // true
![](https://img.haomeiwen.com/i3378249/564460bd7a012714.png)
- 优点
肥肠纯粹的继承关系,实例是子类的实例,也是父类的实例
父类新增的原型实行方法,子类都可以访问到
简单 - 缺点
可以在构造器中给子类新增属性和方法,但是要想给子类的原型扩展属性和方法必须要在new XXX(赋值语句之后,不然会给覆盖)
无法实现多继承
创建子类实例时,无法向父类构造函数传参
来自原型对象的引用属性是所有实例共享的
构造继承
使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
// 构造继承
function Cat(name) {
Animal.call(this);
this.name = name || 'goudaner'
}
let cat = new Cat()
console.group()
console.log(cat.name)
cat.sleep()
console.log(cat instanceof Animal)
console.log(cat instanceof Cat)
cat.eat('鱼')
![](https://img.haomeiwen.com/i3378249/7853ff3f4a8552d5.png)
- 优点
子类不共享父类引用属性
创建子类时可以向父类传递参数
可以实现多继承(call多个父类对象) - 缺点
实例并不是父类的实例,只是子类的实例
只能继承父类的属性和方法,不能继承父类原型属性和方法
不能实现函数复用,每个子类都有父类实例函数的副本,影响性能
实例继承
为父类实例添加新特性,作为子类实例返回
function Cat(name){
var _Cat = new Animal();
_Cat.name = name || 'goudaner';
_Cat.lname = 'sigoudaner';
return _Cat; // 将父类的实例添加新特性之后,作为子类的实例返回
}
// 声明实例可以有两种方式
let cat = new Cat()
let cat = Cat()
console.group()
console.log(cat.name)
console.log(cat.lname)
cat.sleep()
cat.eat('鱼')
console.log(cat instanceof Animal) // true
console.log(cat instanceof Cat) // false
- 优点
不限制调用方式 - 缺点
实例是父类的实例,不是子类的实例
不支持多继承
组合继承
将原型链继承和构造继承组合使用
function Cat(name){
Animal.call(this);
this.name = name || 'goudaner';
}
// 比构造继承就多了下面这句话
Cat.prototype = new Animal();
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
- 优点
集成了原型链继承和构造继承的优点 - 缺点
调用了两次父类构造器,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
但是,仅仅是多消耗了一点内存;
es6实现继承
相对于继承更加友好
class Cat extends Animal {
constructor(name) {
super()
this.name = name
}
say() {
console.log('喵~')
}
}
let cat = new Cat('goudaner')
console.group()
console.log(cat.name)
cat.sleep()
cat.eat('鱼')
cat.say()
console.log(cat instanceof Animal)
console.log(cat instanceof Cat)
![](https://img.haomeiwen.com/i3378249/9a1cfd6759e80f94.png)
- 优点
相对于之前来说更加友好
关于原理请点击详情
网友评论