前言
本文详细详解了js继承的六种方式,保证一看就懂,例子非常贴和,毫无违和感。如果对答案有不一样见解的同学欢迎评论区补充讨论,当然有问题,也欢迎在评论区指出。
切记:学习js继承,需要前置知识,必须要理解并掌握原型链的使用,以及会使用构造函数新增属性/方法的方式
-
这篇文章原型链讲的非常好blog.csdn.net/cc188688768…
-
构造函数新增属性/方法的方式juejin.cn/post/699692…
学习就是这么简单,你听懂了吗?
要继承的父类构造函数
function Father(name) {
this.name = name;
this.say = function(){
console.log('111')
}
}
如何将父类(Father)属性和方法继承到子类(Son)呢
1、原型链继承
function Son(age){
this.age = age;
}
console.log(Son.prototype)//{}
Son.prototype = new Father();
console.log(Son.prototype)//Father { name: undefined, say: [Function (anonymous)] }
const son1 = new Son(12);
console.log(son1)//Father { age: 12 }
console.log(son1.__proto__) //Father { name: undefined, say: [Function (anonymous)] }
重点:让新实例的原型等于父类的实例
缺点:
- 新实例无法向父类构造函数传参
- 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2、借助构造函数
//解决了原型链的两大问题
function Son(name,age){
Father.call(this,name);
this.age = age;
}
Father.prototype.play = function (){
console.log('222')
}//父类原型上的属性/方法
const son = new Son('hzy',12);
console.log(son) //Son { name: 'hzy', say: [Function (anonymous)], age: 12 }
console.log(Son.prototype) //{}
重点:用call()或apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制)
缺点:
- 无法实现构造函数的复用。(每次用每次都要重新调用)
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
3、组合继承(前两种结合)
//使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
function Son(name,age){
this.age = age;
Father.call(this,name);
}
Son.prototype = new Father('hzy');
const son = new Son('jack',12);
console.log(son) //Father { age: 12, name: 'jack', say: [Function (anonymous)] }
console.log(son.__proto__) //Father { name: 'hzy', say: [Function (anonymous)] }
重点:结合了两种模式的优点,传参和复用
缺点:调用了两次父类构造函数(耗内存)
4、原型式继承
// 类似Object.create的实现
function myCreate(proto) {
function F(){}
F.prototype = proto;
return new F();
}
console.log(myCreate(new Father('hzy')).__proto__)
5、寄生式继承
function myCreate(proto) {
function F(){}
F.prototype = proto;
return new F();
}
// 在原型式继承的基础上做一些增强
function Son(father){
var clone = myCreate(father);//通过调用函数创建一个新对象
clone.play = function () {//以某种方式来增强这个对象
console.log("222");
};
return clone; //返回这个对象
}
const son = new Son(new Father('hzy'))
console.log(son) //Father { play: [Function (anonymous)] }
son.play() //222
重点:在原型式继承的基础上做一些增强
缺点:无法实现构造函数的复用,与借助构造函数式类似。
6、寄生式组合继承(最优)
Father.prototype.play = () => {
console.log(222);
}; //可以增强父类
function Son(age,name) {
Father.call(this,name);//可以继承父对象,并且可以向父类传参name
this.age = age;
}
Son.prototype = Object.create(Father.prototype);//继承父类原型上的属性
Son.prototype.constructor = Son;//修复constructor
const son = new Son(12,'hzy')
console.log(son.name,son.__proto__.constructor) //[Function: Son]
重点:结合了组合继承和寄生式继承两者
总结
觉得写得好的,对你有帮助的,可以分享给身边人,知识越分享越多,千万不要吝啬呀
后续更新前端面试手写js高频题目相关,请关注我,整理好,分享给你们,我们一起学前端。