聊聊js的继承
程序员鱼乐,全网同名,分享编程知识与生活日常。还是个小菜狗,喜欢分享知识,如有错误还请大佬们指出,欢迎大佬评论区补充知识。
本篇博客参考作者:卷帘依旧,感谢原作者的博客让我对js继承这部分更加了解。
面向对象语言支持两种继承方式,接口继承和实现继承。接口继承只继承方法的签名,实现继承则继承实际的方法。js中的函数没有签名,因此只支持实现继承。
js实现继承的常用方法:
-
原型链实现继承
所有的引用数据类型都有**__proto__属性,比如一个对象,当我们试图拿到这个对象的某个属性或方法时,如果没有找到这个属性或方法,就会从这个对象的__proto__属性指向的构造函数中的__prototype__属性中去查找这个属性或者方法。如果还有找到,就继续重复这个过程去查找,就组成了我们平时说的原型链**。原型链可以让一个引用数据类型拿到另外一个引用数据类型的属性或方法,因此也就使代码复用,实现了继承。
-
代码:
// 原型链实现继承 function Parent(){ this.name = '鱼乐' this.children = ['A', 'B'] } Parent.prototype.getDetail = function(){ console.log(`姓名:${this.name}`) } function Children(){ } // 子类的原型指向父类父一个实例 Children.prototype = new Parent let childrenOne = new Children() console.log(childrenOne.name) // 鱼乐 childrenOne.children.push('childrenOne') console.log(childrenOne.children) // [ 'A', 'B', 'childrenOne' ] let childrenTwo = new Children() console.log(childrenTwo.name) // 鱼乐 childrenTwo.children.push('childrenTwo') console.log(childrenTwo.children) // [ 'A', 'B', 'childrenOne', 'childrenTwo' ] // !!! // 通过两个实例,我们可以发现原型链继承有两个缺点: // 1、父类的属性被所有子类的实例共享 // 2、在创建子类实例的时候,不能向父类传参
-
缺点:
- 父类的属性被所有子类的实例共享
- 在创建子类实例时,不能向父类传递参数
-
-
构造函数实现继承
-
代码:
// 构造函数实现继承 function Parent(name, age){ this.name = name, this.age = age, this.children = ['A', 'B'] this.getDetail = function(){ console.log(`姓名:${name},年龄:${age}`) } } // 子类构造函数直接调用父类构造函数 function Children(name, age){ Parent.call(this, name, age) } let childrenOne = new Children('childrenOne', 18) childrenOne.getDetail() // 姓名:childrenOne,年龄:18 childrenOne.children.push('childrenOne') console.log(childrenOne.children) // [ 'A', 'B', 'childrenOne' ] let childrenTwo = new Children('childrenTwo', 20) childrenTwo.getDetail() // 姓名:childrenTwo,年龄:20 childrenTwo.children.push('childrenTwo') console.log(childrenTwo.children) // [ 'A', 'B', 'childrenTwo' ] // !!! // 通过上面两个子类实例,我们可以发现通过构造函数实现继承可以解决用原型链实现继承所产生的两个问题: // 1、在创建子类实例的时候可以传参 // 2、父类的属性不会被所有子类实例共享 // 构造函数实现继承的缺点:子类构造函数内部直接调用父类构造函数,每次创建子类实例的时候,都会创建一遍方法,函数的复用就无从谈起了
-
优点:
- 在创建子类实例时,可以向父类传参
- 父类属性不会被所有子类实例共享
-
缺点:
- 每次在创建子类实例时,都会创建一遍方法,函数的复用无从谈起
-
-
组合实现继承
-
代码:
// 组合实现继承 // 结合原型链实现继承和构造函数实现继承的优点 function Parent(name, age){ this.name = name this.age = age this.children = ['A', 'B'] } Parent.prototype.getDetail = function() { console.log(`姓名:${this.name},年龄:${this.age}`) } function Children(name, age){ Parent.call(this, name, age) } Children.prototype = new Parent() let childrenOne = new Children('childrenOne', 18) childrenOne.getDetail() // 姓名:childrenOne,年龄:18 childrenOne.children.push('childrenOne') console.log(childrenOne.children) // [ 'A', 'B', 'childrenOne' ] let childrenTwo = new Children('childrenTwo', 28) childrenTwo.getDetail() // 姓名:childrenTwo,年龄:28 childrenTwo.children.push('childrenTwo') console.log(childrenTwo.children) // [ 'A', 'B', 'childrenTwo' ] // !!! // 组合实现继承可以解决三个问题: // 1、可以使父类方法复用 // 2、每个子类实例的属性是独立的 // 3、在创建子类实例时可以传参
-
优点(就是结合了原型链和构造函数的优点)
- 可以使父类方法复用
- 每个子类实例的属性是独立的
- 在创建子类实例时可以传参
-
js实现继承的其他方法:
因为目前接触不到其他这些方法,所以目前我个人只是作为了解,感兴趣可以参考这篇博客:https://juejin.cn/post/6844904161071333384#heading-3
- 原型式继承
- 寄生式继承
- 寄生组合式继承
- 增强型寄生组合式继承
你在项目中用到过继承吗?
这我也没怎么用过呀,有大佬知道吗?我当时是这样回答的比如在Vue2中给vue挂载一个全局属性,或者将axios挂载到vue上,比如vue.prototype.$axios = axios,然后面试官问我这属于那种继承,我说原型链式继承,她说不对,这是组合式继承。有大佬可以讲讲场景应用这块嘛?
总结
有好几次面试官都问到js的继承了,所以对这块再复习复习。一般面试官就会问js实现继承的方式有哪些?你在项目中有用到过吗?