一、原型链继承(类式继承)
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
this.name = name;
}
Son.prototype = new Person(); //类式继承
var son1 = new Son('son1Name')
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType
让新势实例的原型等于父类的实例
** 特点:**
- 继承了实例的构造函数属性
- 继承了父类构造函数属性
- 继承了父类原型属性
** 缺点:**
- 新实例无法向父类构造函数传参
- 引用类型会被子类的所有实例化对象共享(一个实例修改,另一个实例也会跟着被修改)
二、借用构造函数继承
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
Person.call(this)// 构造函数
this.name = name;
}
var son1 = new Son('son1Name')
console.log(son1.name); // sonName
console.log(son1.age); // underfind
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // false
console.log(son1.sum()); // per1
console.log(son1.sayName()); // 报错
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // underfind
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // false
console.log(son2.sum()); // per1
console.log(son2.sayName()); // 报错
用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
** 特点:**
- 只继承了父类构造函数的属性、方法,没有继承父类原型的属性、方法
- 在子类中可以向附实例传参
- 可以继承多个构造函数属性
- 更改本实例的引用属性其余实例不会更改
** 缺点:**
- 只能继承构造函数的属性
- 无法实现函数复用(每次都需要重新调用)
- 每个实例都有父类构造的副本,臃肿
三、组合继承
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
Person.call(this) //组合式
this.name = name;
}
Son.prototype = new Person() //组合式
var son1 = new Son('son1Name')
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType
采用原型链和构造函数的组合
** 特点:**
- 可以继承父类原型上属性和方法,可以传参,可复用。
- 每个实例所引入的构造函数属性是私有的。
** 缺点:**
- 调用了两次父类构造函数(耗内存)
四、原型式继承
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
this.name = name;
}
var per1 = new Person() //原型式
Son.prototype = Object.create(per1) //原型式
Son.prototype.constructor = Son //原型式
var son1 = new Son('son1Name')
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType
原型式继承的是对类式继承的一个封装,它的内部构造了一个空的函数,将这个函数的原型对象赋予父对象的值,然后返回一个空函数的实例对象。
function F(obj){};
F.prototype = obj //obj是父对象
return new F();
它的缺点与类式继承是一样的,父类的引用类型会被共用。只是它构造了一个空函数,开销会小一点。
五、寄生式继承
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
this.name = name;
}
var per1 = new Person() //寄生式
per1.inherit = 'inherit'; //寄生式
per1.inherit2 = 'inherit2' //寄生式
Son.prototype = Object.create(per1) //寄生式
Son.prototype.constructor = Son //寄生式
var son1 = new Son('son1Name')
console.log(son1.inherit); // inherit
console.log(son1.inherit2); // inherit2
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.inherit); // inherit
console.log(son2.inherit2); // inherit2
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3,'1111']
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType
寄生式继承顾名思义,它可以对继承的对象进行扩展,为其增加新的属性和方法
六、寄生组合式继承
function Person(){
this.type = 'father';
this.arr = [1,2,3]
this.sum = function(){
return 'per1'
}
}
Person.prototype.age = 99;
Person.prototype.sayName = function(){
return 'superType'
}
function Son(name){
Person.call(this)寄生组合式
this.name = name;
}
Son.prototype = Object.create(Person.prototype)寄生组合式
Son.prototype.constructor = Son 寄生组合式
var son1 = new Son('son1Name')
console.log(son1.name); // sonName
console.log(son1.age); // 99
console.log(son1.type); // 'father'
console.log(son1.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son1 instanceof Person); // true
console.log(son1.sum()); // per1
console.log(son1.sayName()); // superType
son1.type = 'newFather'
son1.age = 101
son1.arr.push('1111')
var son2 = new Son('son2Name')
console.log(son2.name); // son2Name
console.log(son2.age); // 99
console.log(son2.type); // 'father'
console.log(son2.arr); // [1,2,3]
console.log(son2 instanceof Son); // true
console.log(son2 instanceof Person); // true
console.log(son2.sum()); // per1
console.log(son2.sayName()); // superType
使用
Object.create()方法还有一个小瑕疵,它需要抛弃默认的Son.prototype,重新创建了一个对象,不能修改已有的默认对象。因此ES6之后又添加了一个辅助函数Object.setPrototypeOf(),直接修改对象的[[prototype]]关联。
Son.prototype = Object.create(Person.prototype)
Son.prototype.constructor = Son
// 可以替换为
Object.setPrototypeOf(Son.prototype,Person.prototype)
继承的原型链图谱
** es5的组合继承:**
** es6的class继承:**