本文深入解析 JavaScript 基于原型的继承机制,阐明 ES6 Class 仅是语法糖的本质。通过 People 与 Hero 类的继承示例,图解实例、构造函数与原型对象间的 __proto__ 指向关系,揭示原型链查找属性与方法的全过程。最后,基于原型链原理实现一个简易 jQuery 库,展示选择器封装、DOM 操作扩展及事件绑定的实际应用。
原型链
尽管 ES6 引入了 class 关键字,但 JavaScript 底层依然基于原型机制运行,class 本质上只是构造函数的语法糖。
以定义一个 People 类为例:
class People {
constructor(props) {
this.name = props.name;
}
run() {
console.log('run')
}
}
使用 new People 实例化该类,可以创建出张三、李四等多个对象实例。
let lisi = new People('李四')
在人群中,存在一类特殊个体,我们将其定义为超级英雄类 Hero。
class Hero extends People {
constructor(props) {
super(props);
this.power = props.power
}
heyHa() {
alert(this.power)
}
}
Hero 类通过继承 People 类,使得英雄首先具备人类的特征(如拥有 run 方法),同时拥有普通人类不具备的超能力 heyHa 方法。我们可以创建一个名为 Jinx 的英雄实例,并赋予其 cannon 超能力:
let Jinx = new Hero({ name: 'jinx', power: 'cannon!' })
虽然实例 Jinx 自身未定义 run 方法,但通过原型链机制,可以向上查找至 People 的原型对象,从而获取 run 方法。这体现了实例的隐式原型 __proto__ 指向其构造函数的原型对象。

当访问实例的方法或属性时,JavaScript 引擎会从实例自身开始查找,若未找到则沿原型链向上回溯,直至找到目标或到达原型链末端。
Jinx.heyHa() // cannon!
// 当自身有该方法时
Jinx.run = () => console.log('i just fly!')
Jinx.run() // i just fly!
那么 People.prototype.__proto__ 指向哪里呢?Object.prototype,在浏览器控制台中执行相关代码可以观察到:

而 Object.prototype 的 __prototype__ 等于 null,这标志着原型链的终点是 null。

至此,完整的原型链结构图示如下:

我们可以利用原型链的特性,实现一个简易版的 jQuery 库。
class JQuery {
constructor(selector, nodeList) {
const res = nodeList || document.querySelectorAll(selector);
const length = res.length;
for (let i = 0; i < length; i++) {
this[i] = res[i]
}
this.length = length;
this.selector = selector;
}
eq(index) {
return new JQuery(undefined, [this[index]]);
}
each(fn) {
for(let i = 0; i < this.length; i ++) {
const ele = this[i]
fn(ele)
}
return this;
}
on(type, fn) {
return this.each(ele => {
ele.addEventListener(type, fn, false)
})
}
// 扩展其他 DOM API
}
const $$ = (selector) => new JQuery(selector);
$$('body').eq(0).on('click', () => alert('click'));
在控制台运行上述代码,执行结果如下:

总结
本文到此结束,希望能为读者提供有益的帮助,也欢迎持续关注本站以获取更多内容!