js对象继承
现有一个父类:
function People(name){
//属性
this.name = name
//实例方法
this.sleep=function(){
console.log(this.name + '正在睡觉')
}
}
//原型方法
People.prototype.eat = function(food){
console.log(this.name + '正在吃:' + food);
}
我们现在要构造一个子类woman,woman需要拥有people的属性和方法
1.原型链继承
function People(name){
//属性
this.name = name || Annie
//实例方法
this.sleep=function(){
console.log(this.name + '正在睡觉')
}
}
//原型方法
People.prototype.eat = function(food){
console.log(this.name + '正在吃:' + food);
}
function Woman(){
}
Woman.prototype= new People('haha');
let womanObj = new Woman();
womanObj.sleep() //haha正在睡觉
womanObj.eat('xiangjiao') //haha正在吃:xiangjiao
缺点:womanObj中的name是唯一的,因为Woman.prototype= new People('haha'),Woman继承时以及传入了name,因此按需构造多个实例。
2.构造继承
function Woman(name){
//继承了People
People.call(this,name);
}
let womanObj = new Woman('haha');
womanObj.sleep() //haha正在睡觉
womanObj.eat('xiangjiao') // Uncaught TypeError: womanObj.eat is not a function
优点:解决了无法构造多个实例的缺点,同时父类可以有多个,只需要在Women中使用call就可以了,例如增加多一个父类People2.call();
缺点:但同时也带来了问题:无法继承父类中原型链上的方法,例如本例中womanObj中调用eat导致报错。
3.实例继承
function Woman(name){
let instance = new People();
instance.name = name
return instance;
}
let womanObj = new Woman('haha');
console.log(womanObj instanceof People) //true
console.log(womanObj instanceof Woman) //false
womanObj.sleep() //haha正在睡觉
womanObj.eat('xiangjiao') //haha正在吃:xiangjiao
解决了原型链的继承的问题,但实际上womanObj是people的实例,而不是woman的实例了,有点借壳上市的感觉。
4.组合继承
function Woman(name){
People.call(this,name)
}
Woman.prototype = People.prototype;
let womanObj = new Woman('haha');
Woman.prototype.constructor = Woman; //为了让constructor从people指向women
console.log(womanObj instanceof Woman) //true
console.log(womanObj instanceof People) //true
womanObj.sleep() //haha正在睡觉
womanObj.eat('xiangjiao') //haha正在吃:xiangjiao
效果其实和实例继承差不多。缺点是调用了两次父类,同时在Women.prototype上写东西会污染People.prototype
例如:
Woman.prototype.food = 'pingguo'
console.log(People.prototype.food) // pingguo
想不污染people.prototype其实改动一行就可以了:
Woman.prototype = Object.create(People.prototype)
这其实和下面讲到的寄生组合继承思想是相类似的。
5.寄生式组合继承
function Woman(name){
//继承父类属性
People.call(this,name)
}
//继承父类方法
(function(){
// 创建空类
let Super = function(){};
Super.prototype = People.prototype;
//父类的实例作为子类的原型
Woman.prototype = new Super();
})();
//修复构造函数指向问题
Woman.prototype.constructor = Woman;
Woman.prototype.food = 'pingguo'
console.log(People.prototype.food) //undefined
let womanObj = new Woman('haha');
console.log(womanObj instanceof Woman) //true
console.log(womanObj instanceof People) //true
womanObj.sleep() //haha正在睡觉
womanObj.eat('xiangjiao') //haha正在吃:xiangjiao
所谓寄生,就是把Woman.prototype寄生在了super对象上,这样Women.prototype上的属性和方法就不会污染到People.prototype
6.ES6继承
class People{
constructor(name='wang'){
this.name = name;
}
eat(){
console.log(`${this.name} eat food`)
}
}
class Woman extends People{
}
let womanObj=new Woman('xiaoxiami');
womanObj.eat() //xiaoxiami eat food
优点:代码简单,没有原型链等概念,继承效果好。