理解 JavaScript 原型机制的核心原理
掌握 prototype 与 [[Prototype]] 的区别与联系
学会通过原型实现方法共享与继承
能够扩展内置对象(如 Array、String)的功能
理解原型链的查找机制及其在内存优化中的作用
在 JavaScript 中,一切皆对象,包括函数、数组、字符串等。JavaScript 采用基于原型的继承模型,而非传统面向对象语言中的类继承。
原型可以理解为“模具”:所有由该模具制造出的实例,都共享模具上的属性和方法。
// 向 Object 的原型添加方法
Object.prototype.sayHi = function() {
console.log("你好,来自对象原型!");
};
const user = { name: "张三" };
user.sayHi(); // 输出:你好,来自对象原型!关键点:
每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 或 Object.getPrototypeOf() 访问)
函数对象额外拥有一个可写的 prototype 属性,用于定义其构造实例的原型
当访问对象属性时,若自身没有,则沿原型链向上查找
谨慎使用
为数组添加实用方法:
// 添加获取首个元素的方法
Array.prototype.first = function() {
return this.length > 0 ? this[0] : undefined;
};
// 添加求和方法
Array.prototype.sum = function() {
let total = 0;
for (let i = 0; i < this.length; i++) {
total += this[i];
}
return total;
};
const scores = [85, 92, 78, 96];
console.log(scores.first()); // 85
console.log(scores.sum()); // 351注意:扩展内置原型可能引发命名冲突或影响第三方库,生产环境中应谨慎使用,或使用
Symbol避免污染。
对比两种定义方法的方式:
// 不推荐:每次创建实例都新建函数
function BadPerson(name) {
this.name = name;
this.greet = function() {
return `你好,${this.name}`;
};
}
// 推荐:方法定义在原型上
function GoodPerson(name) {
this.name = name;
}
GoodPerson.prototype.greet = function() {
return `你好,${this.name}`;
};
const p1 = new BadPerson("小明");
const p2 = new GoodPerson("小红");
// p1.greet 和 p2.greet 是不同函数(BadPerson)
// p2.greet 与其他 GoodPerson 实例共享同一函数实例级扩展
function User(name) {
this.name = name;
}
const user1 = new User("王五");
const user2 = new User("赵六");
// 仅为 user1 添加专属方法
user1.debugInfo = function() {
return `调试信息:用户 ${this.name}`;
};
console.log(user1.debugInfo()); // 调试信息:用户 王五
console.log(user2.debugInfo); // undefined(未定义)适用于需要个别实例特殊行为的场景。
JavaScript 使用原型链实现继承:
// 父类
function Animal(species) {
this.species = species;
}
Animal.prototype.describe = function() {
return `这是一只 ${this.species}`;
};
// 子类
function Bird(name, color) {
// 调用父类构造函数,初始化继承属性
Animal.call(this, "鸟");
this.name = name;
this.color = color;
}
// 设置原型继承
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird; // 修复 constructor 指向
// 子类特有方法
Bird.prototype.fly = function() {
return `${this.name} 正在飞翔!`;
};
// 重写父类方法
Bird.prototype.describe = function() {
return `${this.name} 是一只 ${this.color} 的 ${this.species}`;
};
const parrot = new Bird("小绿", "绿色");
console.log(parrot.describe()); // 小绿 是一只 绿色 的 鸟
console.log(parrot.fly()); // 小绿 正在飞翔!关键步骤:
使用
Parent.call(this, ...)调用父构造函数用
Object.create(Parent.prototype)建立原型链修正
constructor指向

JavaScript 中所有对象最终都继承自 Object.prototype:
Object.prototype.universalMethod = function() {
console.log("我是万物皆可调用的方法");
};
const obj = { x: 1 };
const arr = [1, 2, 3];
const str = "hello";
function fn() {}
obj.universalMethod(); // ✓
arr.universalMethod(); // ✓
str.universalMethod(); // ✓
fn.universalMethod(); // ✓这是因为:
数组 → Array.prototype → Object.prototype
字符串 → String.prototype → Object.prototype
函数 → Function.prototype → Object.prototype
整个结构形成一棵以 Object.prototype 为根的树状原型链。
每个函数都有 prototype 属性,每个对象都有 [[Prototype]] 内部链接
实例通过 __proto__ 指向其构造函数的 prototype
属性查找沿原型链向上进行,直到 null
方法应优先定义在原型上以节省内存
使用 Object.create(Parent.prototype) 实现安全的原型继承
扩展内置原型需谨慎,避免全局污染
箭头函数没有 prototype 属性,也不能作为构造函数使用
为什么 Function.prototype 的 [[Prototype]] 指向 Object.prototype,而 Object 本身又是 Function 的实例?这是否构成循环依赖?请解释 JavaScript 引擎如何处理这一关系。
编写一个 MyArray 构造函数,使其继承自原生 Array,并添加 average() 方法计算平均值。要求新数组实例仍能使用 push、pop 等原生方法。
如果同时向 Array.prototype 和某个具体数组实例添加同名方法(如 customMethod),调用时会执行哪一个?为什么?请结合原型链查找规则说明。