JavaScript prototype

每个 JavaScript 函数都有一个 prototype(原型)属性,每个对象都有一条隐藏的原型链。原型机制实现了属性与方法的共享以及继承:new 出来的实例自己身上没有的方法,会沿原型链向上找到构造函数的 prototype。它是理解继承、class(本质是原型的语法糖)以及"数组为什么有 map"这类问题的钥匙。

构造函数与 prototype

把方法挂在构造函数的 prototype 上,所有实例共享同一个方法,不必为每个实例各复制一份:

function Person(name) {
  this.name = name; // 实例自有的属性
}
// 共享方法:挂在原型上
Person.prototype.sayHi = function () {
  console.log("你好," + this.name);
};

const p1 = new Person("小明");
const p2 = new Person("小红");
p1.sayHi(); // 输出:你好,小明
p2.sayHi(); // 输出:你好,小红
console.log(p1.sayHi === p2.sayHi); // 输出:true(同一个函数,共享)

原型链:属性查找过程

访问 p1.name 时,先查实例自身;找不到就去 Person.prototype;还没有就继续向上到 Object.prototype,直到 null 为止:

function Animal() {}
Animal.prototype.kind = "动物";

const dog = new Animal();
console.log(dog.kind);     // 输出:动物(在原型上找到)
console.log(dog.toString); // 函数(在 Object.prototype 上找到)

这条"实例 → 构造函数原型 → Object.prototype → null"的链路就是原型链

三个常用判断工具

  • obj.hasOwnProperty("x"):判断属性是否为自身属性(而非继承来的)。
  • "x" in obj:自身或原型链上有都算 true。
  • 查看原型:标准写法 Object.getPrototypeOf(obj),旧写法 obj.proto
function Person(name) { this.name = name; }
Person.prototype.age = 20;

const p = new Person("小明");
console.log(p.hasOwnProperty("name")); // 输出:true(自身属性)
console.log(p.hasOwnProperty("age"));  // 输出:false(来自原型)
console.log("age" in p);               // 输出:true(原型上有也算有)
console.log(Object.getPrototypeOf(p) === Person.prototype); // 输出:true

用原型实现继承

把子类构造函数的 prototype 指向父类的实例(或 Object.create(父.prototype)),子类实例就能调用父类原型上的方法;记得把 constructor 指回子类自己:

function Animal() {}
Animal.prototype.eat = function () { console.log("吃饭"); };

function Dog() {}
Dog.prototype = Object.create(Animal.prototype); // 继承 Animal
Dog.prototype.constructor = Dog;                 // 修正 constructor 指向
Dog.prototype.bark = function () { console.log("汪汪"); };

const d = new Dog();
d.eat();  // 输出:吃饭(继承来的方法)
d.bark(); // 输出:汪汪(自己的方法)

ES6 的 class extends 底层就是这套机制:现在写继承用 class 更简洁,但原理仍是原型链。

原型是"活"的,修改要谨慎

运行期往原型上加方法,已创建的实例立刻就能用;反之不要随意修改 Object.prototype、Array.prototype,否则会污染所有对象,可能引发性能与兼容问题:

function Person() {}
const p = new Person();

Person.prototype.say = function () { console.log("后来加的方法"); };
p.say(); // 输出:后来加的方法(实例无需重新创建)

小结

prototype 是 JS 实现共享与继承的机制:方法挂到原型避免重复占用、属性查找沿原型链逐级向上、hasOwnProperty 区分自有与继承属性、Object.create 搭起继承链。理解原型链,才算真正读懂了 JavaScript 的对象世界。

笔记加载中…