JavaScript .prototype工作原理详解

JavaScript .prototype工作原理详解

技术背景

在传统的面向对象编程语言(如 Java、C# 或 C++)中,使用类作为对象的蓝图,通过类创建对象或扩展类。而 JavaScript 没有类的概念,它采用基于原型的继承方式,即先创建对象,然后可以对对象进行扩展或基于它创建新对象。理解 JavaScript 的 .prototype 对于掌握 JavaScript 的面向对象编程至关重要。

实现步骤

1. 定义构造函数和原型方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义一个构造函数来表示 Person 对象
var Person = function(name) {
this.name = name;
};

// 为 Person 的原型添加一个 getName 方法
Person.prototype.getName = function() {
return this.name;
};

// 创建一个 Person 类型的新对象
var john = new Person("John");

// 调用 getName 方法
console.log(john.getName());

2. 动态扩展原型

1
2
3
4
5
6
7
// 为 Person 的原型添加一个 sayMyName 方法
Person.prototype.sayMyName = function() {
console.log('Hello, my name is ' + this.getName());
};

// 调用新方法
john.sayMyName();

3. 实现继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 定义一个 Customer 构造函数
var Customer = function(name) {
this.name = name;
};

// 将 Customer 的原型设置为 Person 的一个实例
Customer.prototype = new Person();

// 创建一个 Customer 类型的新对象
var myCustomer = new Customer('Dream Inc.');

// 调用 Person 的方法
myCustomer.sayMyName();

// 为 Customer 的原型添加新方法
Customer.prototype.setAmountDue = function(amountDue) {
this.amountDue = amountDue;
};

Customer.prototype.getAmountDue = function() {
return this.amountDue;
};

// 调用新方法
myCustomer.setAmountDue(2000);
console.log(myCustomer.getAmountDue());

核心代码

模拟 new 关键字的实现

1
2
3
4
5
6
7
8
9
function Person(name) {
this.name = name;
}
my_person_prototype = { getName: function() { console.log(this.name); } };

// 模拟 new 关键字的步骤
var newObject = Object.create(my_person_prototype);
Person.call(newObject, "George");
newObject.getName();

实现继承的另一种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function() { return 'this is inherited' };

function inherit(child, parent) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
return child;
}

Child = inherit(Child, Parent);
const o = new Child();
console.log(o.inheritedMethod());

最佳实践

共享方法

将共享的方法添加到构造函数的 .prototype 属性上,这样所有实例都可以共享这些方法,节省内存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function KeyValueStore() {
this.data = {};
}

KeyValueStore.prototype.get = function(key) {
return this.data[key];
};

KeyValueStore.prototype.set = function(key, value) {
this.data[key] = value;
};

var store = new KeyValueStore();
store.set('key', 'value');
console.log(store.get('key'));

使用 Object.create 创建对象

1
2
3
4
5
6
7
8
9
var personPrototype = {
getName: function() {
return this.name;
}
};

var person = Object.create(personPrototype);
person.name = "Alice";
console.log(person.getName());

常见问题

1. prototype[[Prototype]] 的区别

  • .prototype 是函数的一个属性,它是一个对象,用于在使用 new 关键字创建对象时,将该对象的 [[Prototype]] 指向这个 .prototype 对象。
  • [[Prototype]] 是所有对象都有的一个内部属性,它指向该对象的原型对象,通过 Object.getPrototypeOf() 方法可以获取该属性。

2. 修改 prototype 的影响

修改构造函数的 .prototype 属性会影响到所有基于该构造函数创建的对象。例如:

1
2
3
4
5
6
7
8
9
10
function Person() {}
var person1 = new Person();

Person.prototype.sayHello = function() {
console.log('Hello');
};

var person2 = new Person();
person1.sayHello();
person2.sayHello();

3. __proto__ 的使用

__proto__[[Prototype]] 的一个访问器属性,但它已经被弃用。建议使用 Object.getPrototypeOf()Object.setPrototypeOf() 方法来操作对象的原型。

1
2
3
4
function Person() {}
var person = new Person();
var prototype = Object.getPrototypeOf(person);
console.log(prototype === Person.prototype);

JavaScript .prototype工作原理详解
https://119291.xyz/posts/javascript-prototype-working-principle-explanation/
作者
ww
发布于
2025年5月20日
许可协议