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
| var Person = function(name) { this.name = name; };
Person.prototype.getName = function() { return this.name; };
var john = new Person("John");
console.log(john.getName());
|
2. 动态扩展原型
1 2 3 4 5 6 7
| 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
| var Customer = function(name) { this.name = name; };
Customer.prototype = new Person();
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
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); } };
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);
|