471 字
2 分钟
03 · 原型与原型链
第一次没搞懂”方法共享”
早年每个实例都拷贝一份方法,内存爆炸。后来知道 JS 用原型让所有实例共享方法:
function Person(name) { this.name = name; }Person.prototype.greet = function () { return `Hi, ${this.name}`; };
const p1 = new Person("Tom");const p2 = new Person("Jane");p1.greet === p2.greet; // true(方法在原型上,共享)三个容易混的概念
prototype:函数(构造函数)上的属性,指向”实例的原型对象”。__proto__(现代用Object.getPrototypeOf):实例内部指针,指向”创建它的构造函数的prototype”。constructor:原型对象上的属性,指回构造函数本身。
关系:p.__proto__ === Person.prototype,Person.prototype.constructor === Person。
原型链:属性怎么找
访问 p.greet 时,JS 先查 p 自身,没有就沿 p.__proto__(即 Person.prototype)找,再没有继续向上到 Object.prototype,到 null 为止。这条链就是原型链。
p.toString(); // p 自身没有 → Person.prototype 没有 → Object.prototype 有,调用它原型链是 JS 实现继承的机制:子类原型指向父类实例(或父类原型),就能”继承”其属性。
new 操作符做了什么
function myNew(Ctor, ...args) { const obj = Object.create(Ctor.prototype); // 1. 建空对象,原型指向 Ctor.prototype const result = Ctor.apply(obj, args); // 2. this 绑定到 obj,执行构造函数 return typeof result === "object" && result !== null ? result : obj; // 3. 返回对象}理解 new 的三步,就看懂了”为什么实例能访问原型方法”。
小结
- 实例方法放
prototype上共享,省内存。 __proto__是实例到原型的链,prototype是构造函数的原型属性。- 属性查找沿原型链向上,到
Object.prototype→null。 class语法是原型继承的语法糖(下篇讲继承演进)。
练习
- 不用
class,用构造函数 + 原型写一个Animal,让其有共享方法eat()。 - 画出
new Person("Tom")后p、p.__proto__、Person.prototype、Object.prototype之间的指向图。 - 实现上面的
myNew,并用它创建对象验证原型链正确。