JavaScript中原型链(proto)与原型(prototype)
在JavaScript中,理解原型链(__proto__)和原型(prototype)对于深入掌握面向对象编程至关重要。本文将通过示例代码,详细解析__proto__和prototype之间的关系,以及它们在对象和构造函数之间的作用。
一、基本概念
1. 构造函数与实例对象
- 构造函数:在JavaScript中,函数可以作为构造函数使用,通过
new关键字创建实例对象。 - 实例对象:由构造函数创建的对象,继承了构造函数的属性和方法。
2. 原型(prototype)
- prototype:每个函数(包括构造函数)都有一个
prototype属性,指向一个对象,这个对象被称为原型对象。 - 原型对象:存储共享的属性和方法,供所有实例对象访问。
3. 原型链(__proto__)
- proto:每个对象都有一个
__proto__属性,指向创建该对象的构造函数的原型对象。 - 原型链:通过
__proto__属性,将对象、构造函数和原型对象连接起来,形成一个链式结构。
二、示例代码解析
下面通过一段示例代码,逐步解析__proto__和prototype之间的关系。
function Person(name, age){this.name = name;this.age = age;
}const person = new Person('Tom', 18);// 构造函数的prototype就是实例对象的__proto__
console.log(Person.prototype === person.__proto__); // true// 实例对象的constructor指向构造函数
console.log(person.constructor === Person); // true// 实例对象的__proto__对象上的constructor指向的又是Person构造函数
console.log(person.__proto__.constructor === Person); // true// 实例对象的__proto__对象的__proto__指向的是Object构造函数的prototype
console.log(person.__proto__.__proto__ === Object.prototype); // true// 每一个构造函数也是一个对象,所以也都有__proto__属性,指向的是Function构造函数的prototype
console.log(Person.__proto__ === Function.prototype); // true// Function构造函数的prototype的constructor指向Function构造函数
console.log(Function.prototype.constructor === Function); // true// Function的prototype的__proto__指向Object的prototype
console.log(Function.prototype.__proto__ === Object.prototype); // true// 因为所有构造函数的__proto__都是指向Function的prototype,所以Function构造函数的prototype和__proto__是相等的
console.log(Function.__proto__ === Function.prototype); // true
1. 实例对象与构造函数的关系
console.log(Person.prototype === person.__proto__); // true
- 解析:
Person.prototype是构造函数Person的原型对象。person.__proto__是实例对象person的原型,指向Person.prototype。- 因此,
Person.prototype === person.__proto__返回true。
2. 实例对象的constructor属性
console.log(person.constructor === Person); // true
- 解析:
- 实例对象
person的constructor属性指向其构造函数Person。 - 因此,
person.constructor === Person返回true。
- 实例对象
3. 原型对象的constructor属性
console.log(person.__proto__.constructor === Person); // true
- 解析:
person.__proto__是Person.prototype,它有一个constructor属性,指向构造函数Person。- 因此,
person.__proto__.constructor === Person返回true。
4. 原型链向上查找
console.log(person.__proto__.__proto__ === Object.prototype); // true
- 解析:
person.__proto__是Person.prototype。Person.prototype.__proto__指向Object.prototype。- 因此,
person.__proto__.__proto__ === Object.prototype返回true。
5. 构造函数也是对象
console.log(Person.__proto__ === Function.prototype); // true
- 解析:
- 构造函数
Person本身是一个函数对象,所以它的__proto__属性指向Function.prototype。 - 因此,
Person.__proto__ === Function.prototype返回true。
- 构造函数
6. Function构造函数的关系
console.log(Function.prototype.constructor === Function); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true
- 解析:
Function.prototype是Function构造函数的原型对象。Function.prototype.constructor指向Function自身。Function.prototype.__proto__指向Object.prototype,因为函数也是对象。Function.__proto__指向Function.prototype,因为Function也是函数,是自己的构造函数。- 因此,上述三个
console.log均返回true。
三、原型链查找属性的过程
console.log(person.__proto__); // Person {}
console.log(person.__proto__.__proto__); // Object {}
console.log(person.__proto__.__proto__.__proto__); // null
- 解析:
person.__proto__是Person.prototype。person.__proto__.__proto__是Object.prototype。person.__proto__.__proto__.__proto__为null,表示原型链的顶端。
四、总结
1. 关于__proto__和prototype
-
__proto__:- 是每个对象都有的内置属性,指向其构造函数的原型对象。
- 用于实现对象的原型链,在查找属性时,如果对象自身没有,会沿着
__proto__向上查找。
-
prototype:- 是构造函数的属性,指向原型对象。
- 原型对象上定义的方法和属性会被构造函数的所有实例共享。
2. 关于构造函数和实例对象
-
实例对象的
__proto__:- 指向构造函数的
prototype属性。
- 指向构造函数的
-
实例对象的
constructor:- 通过
__proto__找到原型对象,原型对象的constructor指向构造函数。
- 通过
-
构造函数的
__proto__:- 因为构造函数本身是一个函数对象,所以它的
__proto__指向Function.prototype。
- 因为构造函数本身是一个函数对象,所以它的
3. 关于原型链的查找过程
- 当访问对象的属性时,JavaScript引擎会先查找对象自身的属性。
- 如果找不到,会沿着
__proto__属性指向的原型对象继续查找。 - 这个过程会一直持续,直到找到属性或到达原型链的顶端(
null)。
4. 关于Function和Object
-
Function构造函数:
- 是所有函数的构造函数,包括
Function自身。 Function.__proto__ === Function.prototype,因为Function是一个函数,其__proto__指向Function.prototype。
- 是所有函数的构造函数,包括
-
Object构造函数:
- 是所有对象的构造函数,包括
Function.prototype。 Function.prototype.__proto__ === Object.prototype。
- 是所有对象的构造函数,包括
五、深入思考
-
为什么
Function.__proto__ === Function.prototype?- 因为
Function是所有函数的构造函数,包括它自己。Function作为一个函数对象,其__proto__指向Function.prototype。
- 因为
-
为什么
Object.__proto__ === Function.prototype?Object是一个函数(构造函数),所以其__proto__指向Function.prototype。
-
为什么
Function.prototype.__proto__ === Object.prototype?Function.prototype是一个对象,因此其__proto__指向Object.prototype。