前言:
🤡 作者简介:我是Morning,计算机的打工人,想要翻身做主人 🙈 🙈 🙈
🏠 个人主页: Morning的主页
📕系列专栏:前端面试备战
📞 如果小编的内容有欠缺或者有改进,请指正拙著。期待与大家的交流
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏
目录
面试题:你能提一提JS的有关继承么
就需要讲一讲以下的几种继承,将红色字体阐述出来
原型链继承:
让子类的原型指向父类的实例
function Father(){
this.money=30000,
this.arr=[1,2,3]
}
Father.prototype.getMoney=function(){
return `获得了${this.money}`
}
function Son(){}
//子类的原型指向父类的实例
Son.prototype=new Father()
const bigSon=new Son()
console.log(bigSon.money);//30000
console.log(bigSon.getMoney());//获得了30000
const smallSon=new Son()
smallSon.arr.push(5)
console.log(smallSon.arr); //[1, 2, 3, 5]
console.log(bigSon.arr); //[1, 2, 3, 5]
弊端:
<1.>因为只有一个父类的实例作为他们的原型,所以所有实例共享了一个原型上的属性arr,当原型上的属性作为引用类型时,此处是数组,smallSon添加一个新内容会导致bigSon上的arr也改变了。
<2>.子类构造函数不能传递参数到父类原型上。
构造函数继承:
在子类的构造函数中,执行父类的构造方法,并且绑定子类的this(这也是call的实战应用之一,在之后的文章中我会出一期专门来介绍call)
function Father(money){
this.money=[money]
}
function Son(money){
Father.call(this,money)
}
const son1=new Son(10000)
const son2=new Son(20000)
console.log(son1.money,son2.money); //[10000],[20000]
//弊端
//继承不到父类的原型上的属性与方法
Father.prototype.getMoney=function(){
return `获得了${this.money}`
}
Father.prototype.galary=4000
console.log(son1.galary); //undefined
console.log(son1.getMoney()); //ncaught TypeError: son1.getMoney is not a function
弊端:
<1>.继承不到父类的原型上的属性与方法
<2>.两个实例对象都拥有了拷贝来的money属性,所以没有共享属性。但同时也意味着创造一个实例就得拷贝一次父类的所有属性。且因为不能继承父类原型,所以方法不能复用,被迫拷贝方法。
组合式继承:
结合了原型链继承和构造函数继承
function Father(money){
this.money=[money]
}
function Son(money){
Father.call(this,money)第二次调用父类构造函数
}
Son.prototype=new Father()//第一次调用父类构造函数
const son1=new Son(10000)
const son2=new Son(20000)
console.log(son1.money,son2.money); //[10000],[20000]
//可以继承父类的原型上的属性与方法
Father.prototype.getMoney=function(){
return `获得了${this.money}`
}
Father.prototype.galary=4000
console.log(son1.galary); //4000
console.log(son1.getMoney()); //获得了10000
弊端:每一次创建子类实例都会调用两次父类构造函数,降低性能
寄生组合式继承
要改动的代码:
Son.prototype=new Father()//第一次调用父类构造函数
//更改为
Son.prototype=Father.prototype
但如果将父类原型赋值给子类原型的话,在子类原型上添加方法、属性,相应父类上也会添加
function Father(money){
this.money=[money]
}
function Son(money){
Father.call(this,money)
}
Son.prototype=Father.prototype
//在子类原型上添加属性、方法
Son.prototype.fee=[3000]
Son.prototype.getGalary=function(){
console.log('这是子类的方法');
}
var father=new Father()
father.getGalary()//这是子类的方法
console.log(father.fee);//[3000]
其实子类的原型应该为父类的原型的深拷贝
function Father(money){
this.money=[money]
}
function Son(money){
Father.call(this,money)
}
Son.prototype=Object.create(Father.prototype)
//在子类原型上添加属性、方法
Son.prototype.fee=[3000]
Son.prototype.getGalary=function(){
console.log('这是子类的方法');
}
var father=new Father()
console.log(father.fee);//undefined
father.getGalary()//报错,father.getGalary is not a function
ES6 Class继承
以上的继承方式都是通过原型去解决的。在ES6中,我们可以使用class去实现继承,并且实现起来很简单
class Parent{
constructor(value){
this.val=value
}
getValue(val){
console.log(this.val);
}
}
class Children extends Parent{
constructor(value){
super(value)
this.val=value
}
}
let child=new Children(1)
child.getValue() //1
console.log(child instanceof Parent); //true
class实现继承的核心在于使用extends表明继承来自哪个父类,并且在子类的构造函数中必须调用super。这段代码可以看成Parent.call(this,value)
更加具体的class继承大家可以看看此篇文章ES6 | 关于class类 继承总结