首页 > 趣闻 > 正文内容

手把手教你实现JS继承:原型链、组合继承与Class语法对比

趣闻2025-05-19 15:52:48

哎哟喂!昨天隔壁工位的小王又双叒叕崩溃了,对着屏幕直拍大腿:"我明明改了子类的属性,怎么父类也跟着变了?" 你是不是也遇到过这种魔幻现象?别慌,今天咱们就像拆乐高积木一样,把JS继承的三大招式掰扯清楚。

(抓头)先来点灵魂拷问:为什么用原型链继承会共享属性?组合继承为啥要调用两次父类构造函数?ES6的class语法糖到底甜不甜?带着这些疑问,咱们上路!

—— 手动分割线 ——

??第一关:原型链继承??
这玩意儿就像祖传玉佩,子子孙孙都摸同一块:

javascript复制
function 老王家() { this.传家宝 = "青花瓷" }
function 小王() {}
小王.prototype = new 老王家()

const 小王1 = new 小王()
const 小王2 = new 小王()
小王1.传家宝 = "赝品"
console.log(小王2.传家宝) // 输出啥?你猜怎么着?还是"赝品"!

看见没?所有实例共享同一个父类实例的属性,改一个全遭殃。不过话说回来,原型链继承也不是一无是处,比如快速创建简单对象时还挺方便,但要做复杂继承...(摇头)还是算了吧。

—— 手动分割线 ——

??第二关:组合继承??
这时候有人拍案而起:"咱把构造函数和原型链拼一起不就行了?" 于是有了这个缝合怪:

javascript复制
function 老王家(宝贝) {
  this.传家宝 = 宝贝
}
function 小王(宝贝, 新技能) {
  老王家.call(this, 宝贝) // 第一次调用
  this.技能 = 新技能
}
小王.prototype = new 老王家() // 第二次调用

(敲黑板)注意看!父类构造函数被调用了两次。要是老王家构造函数里有耗时操作,比如连接数据库什么的,这性能不得直接拉胯?不过好在实例终于有自己的属性了,也算是个进步。

—— 手动分割线 ——

??第三关:Class继承??
ES6带来的语法糖,甜度五颗星:

javascript复制
class 老王家 {
  constructor(宝贝) {
    this.传家宝 = 宝贝
  }
}

class 小王 extends 老王家 {
  constructor(宝贝, 新技能) {
    super(宝贝)
    this.技能 = 新技能
  }
}

看着是不是清爽多了?不过别被表象骗了,底层还是寄生组合继承那套。有个冷知识:用class写的继承方法,在Chrome调试工具里会显示[[FunctionLocation]]为native code,说明是引擎实现的。

—— 手动分割线 ——

??自问自答时间??
问:这三种方法到底该用哪个?
答:日常开发闭眼选class就对了!但要是维护十年前的老项目...(叹气)还是得懂原型链那套。

问:为什么面试总问组合继承的缺点?
答:就跟考驾照要学倒车入库一个道理,虽然现在有自动泊车了,但基本功得扎实啊!

—— 手动分割线 ——

??实战翻车现场??
去年有个经典案例:某电商网站用原型链继承实现商品分类,结果促销活动时修改子类价格,导致整个品类价格崩盘。最后排查发现,所有子类实例共享同一个父类price属性...(擦汗)看看,不懂继承原理多可怕!

—— 手动分割线 ——

说点掏心窝子的话:别被这些继承方式吓到,就像学骑自行车,刚开始可能摇摇晃晃,等肌肉记忆形成了自然就会了。现在主流框架都用class语法,但偶尔翻看Vue2源码,还能看到寄生组合继承的身影。记住啊,代码是人写的,不是机器自动生成的,多写多错多改才是正道。下次再碰到继承问题,先把这三个方法拉出来遛遛,保准能找到症结所在!

搜索