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 的对象世界。