JavaScript原型链没那么难:一文彻底搞懂

JavaScript原型链没那么难:一文彻底搞懂

1. 原型(Prototype)

什么是原型?

每个 JavaScript 对象都有一个隐藏的 [[Prototype]] 属性,它指向另一个对象,这个被指向的对象就是它的"原型"。

如何访问原型?

javascript

复制代码

// 通过 __proto__ 属性(非标准,但浏览器都支持)

const obj = {};

console.log(obj.__proto__); // 指向 Object.prototype

// 通过 Object.getPrototypeOf()(推荐的标准方式)

console.log(Object.getPrototypeOf(obj)); // 同样指向 Object.prototype

示例:对象的原型

javascript

复制代码

const person = {

name: 'Alice',

age: 25

};

console.log(person.__proto__ === Object.prototype); // true

2. 构造函数与原型

构造函数创建对象

javascript

复制代码

function Person(name, age) {

this.name = name;

this.age = age;

}

// 在原型上添加方法

Person.prototype.sayHello = function() {

console.log(`Hello, I'm ${this.name}`);

};

const alice = new Person('Alice', 25);

const bob = new Person('Bob', 30);

alice.sayHello(); // "Hello, I'm Alice"

bob.sayHello(); // "Hello, I'm Bob"

为什么使用原型?

javascript

复制代码

// 如果不使用原型,每个实例都会有独立的方法副本

function BadPerson(name) {

this.name = name;

this.sayHello = function() { // ❌ 每个实例都有独立的函数

console.log(`Hello, I'm ${this.name}`);

};

}

// 使用原型,所有实例共享同一个方法

function GoodPerson(name) {

this.name = name;

}

GoodPerson.prototype.sayHello = function() { // ✅ 所有实例共享

console.log(`Hello, I'm ${this.name}`);

};

3. 原型链(Prototype Chain)

什么是原型链?

当访问一个对象的属性时,JavaScript 会:

先在对象自身查找

如果找不到,就去它的原型上找

如果还找不到,就去原型的原型上找

直到找到 null 为止

这种一层层的查找关系就形成了"原型链"。

原型链示例

javascript

复制代码

const grandparent = { grandpa: '老爷爷' };

const parent = { papa: '爸爸' };

const child = { child: '孩子' };

// 设置原型链:child -> parent -> grandparent

Object.setPrototypeOf(parent, grandparent);

Object.setPrototypeOf(child, parent);

console.log(child.child); // "孩子" - 自身属性

console.log(child.papa); // "爸爸" - 父级原型属性

console.log(child.grandpa); // "老爷爷" - 祖父级原型属性

console.log(child.xxx); // undefined - 找不到

4. 完整的原型链图示

javascript

复制代码

[你的对象] → Object.prototype → null

[数组对象] → Array.prototype → Object.prototype → null

[函数对象] → Function.prototype → Object.prototype → null

实际代码验证

javascript

复制代码

const arr = [1, 2, 3];

// 数组的原型链

console.log(arr.__proto__ === Array.prototype); // true

console.log(Array.prototype.__proto__ === Object.prototype); // true

console.log(Object.prototype.__proto__); // null

// 函数的原型链

function test() {}

console.log(test.__proto__ === Function.prototype); // true

console.log(Function.prototype.__proto__ === Object.prototype); // true

5. 重要的内置原型

Object.prototype

javascript

复制代码

// 所有对象的最终原型

console.log(Object.prototype.toString()); // "[object Object]"

console.log(Object.prototype.hasOwnProperty); // 检查自身属性的方法

Array.prototype

javascript

复制代码

const arr = [1, 2, 3];

console.log(Array.prototype.push === arr.push); // true

console.log(Array.prototype.map === arr.map); // true

Function.prototype

javascript

复制代码

function test() {}

console.log(Function.prototype.call === test.call); // true

console.log(Function.prototype.bind === test.bind); // true

6. 实际应用场景

1. 继承的实现

javascript

复制代码

function Animal(name) {

this.name = name;

}

Animal.prototype.eat = function() {

console.log(`${this.name} is eating`);

};

function Dog(name, breed) {

Animal.call(this, name); // 调用父类构造函数

this.breed = breed;

}

// 设置原型链继承

Dog.prototype = Object.create(Animal.prototype);

Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {

console.log('Woof!');

};

const myDog = new Dog('Buddy', 'Golden');

myDog.eat(); // "Buddy is eating" (继承的方法)

myDog.bark(); // "Woof!" (自身的方法)

2. 方法扩展(猴子补丁)

javascript

复制代码

// 为数组添加自定义方法

Array.prototype.last = function() {

return this[this.length - 1];

};

const arr = [1, 2, 3, 4];

console.log(arr.last()); // 4

3. 属性检查

javascript

复制代码

const obj = { a: 1 };

console.log(obj.hasOwnProperty('a')); // true - 自身属性

console.log(obj.hasOwnProperty('toString')); // false - 继承属性

console.log('toString' in obj); // true - 包括继承属性

7. 注意事项

1. 性能考虑

javascript

复制代码

// 原型链太长会影响查找性能

for (let key in obj) {

if (obj.hasOwnProperty(key)) { // 只遍历自身属性

console.log(key);

}

}

2. 现代替代方案

javascript

复制代码

// ES6 class 语法(本质还是基于原型)

class Person {

constructor(name) {

this.name = name;

}

sayHello() { // 这个方法会在 Person.prototype 上

console.log(`Hello, ${this.name}`);

}

}

// 等同于

function Person(name) {

this.name = name;

}

Person.prototype.sayHello = function() {

console.log(`Hello, ${this.name}`);

};

总结

概念

说明

示例

原型

每个对象都有一个指向原型的链接

obj.__proto__

原型链

通过原型链接形成的查找链条

obj → proto1 → proto2 → null

作用

实现继承和方法共享

所有数组共享 Array.prototype 的方法

重点

属性查找会沿着原型链向上

obj.toString() 找到 Object.prototype.toString

原型机制是 JavaScript 实现面向对象编程的基础,理解它对于掌握 JavaScript 至关重要!

相关推荐

365bet体育在线总站 弄懂了“掤劲”,你就弄懂了“太极”

弄懂了“掤劲”,你就弄懂了“太极”

📅 09-12 👁️ 4563
365bet体育在线总站 全州世界杯体育场

全州世界杯体育场

📅 09-21 👁️ 3264