JavaScript原型与原型链:深入浅出指南
本文通过代码实例和通俗解释,带你彻底理解JavaScript中最核心的概念之一
什么是原型?
在JavaScript中,原型(Prototype) 是函数天生拥有的一个属性(prototype
),它是一个对象,用于存放可以被所有实例共享的属性和方法。
ini
// 定义构造函数
function Car(color) {
this.color = color;
}
// 在原型上添加共享属性
Car.prototype.name = 'su7-Ultra';
Car.prototype.height = 1.4;
const car1 = new Car('orange');
const car2 = new Car('green');
console.log(car1.name); // 'su7-Ultra'(来自原型)
console.log(car2.height); // 1.4(来自原型)
原型存在的意义:
- 将构造函数中固定的属性和方法挂载到原型上
- 实例创建时无需重复执行这些属性和方法
- 节省内存,提高性能
对象原型(隐式原型)
每个对象都有一个内置属性 __proto__
(隐式原型),它的值指向创建该对象的构造函数的原型(prototype
)。
ini
function Person(name) {
this.name = name;
}
const p1 = new Person('超超');
console.log(p1.__proto__ === Person.prototype); // true
关键概念 :实例对象的隐式原型(__proto__
)等于构造函数的显示原型(prototype
)
new关键字的内部原理
当使用 new
调用构造函数时,会发生以下步骤:
kotlin
function _new(constructor, ...args) {
// 1. 创建一个空对象
const obj = {};
// 2. 将构造函数的this指向这个空对象
// 3. 执行构造函数中的代码
constructor.apply(obj, args);
// 4. 将空对象的隐式原型指向构造函数的原型
obj.__proto__ = constructor.prototype;
// 5. 返回这个对象
return obj;
}
// 实际使用
const car = _new(Car, 'blue');
原型链:JavaScript的继承机制
当访问对象的属性时,JavaScript引擎会:
- 先在对象自身属性中查找
- 如果找不到,则沿着
__proto__
向上查找 - 直到找到
null
为止
这种查找路径形成的链条就是原型链。
ini
function GrandParent() {
this.name = 'grandparent';
}
function Parent() {
this.lastName = '张';
}
function Child() {
this.firstName = '三';
}
// 设置原型链
Parent.prototype = new GrandParent();
Child.prototype = new Parent();
const child = new Child();
console.log(child.name); // 'grandparent'(来自GrandParent)
console.log(child.lastName); // '张'(来自Parent)
原型链的终点
所有原型链的终点都是 Object.prototype
,而 Object.prototype.__proto__
是 null
javascript
console.log(Object.prototype.__proto__); // null
没有原型的对象
使用 Object.create()
可以创建没有原型的对象:
javascript
const obj = Object.create(null); // 没有原型的对象
console.log(obj.toString); // undefined(没有继承Object的方法)
实际应用:数组方法
为什么我们创建的空数组可以直接使用 push()
、pop()
等方法?
javascript
const arr = []; // 相当于 const arr = new Array()
console.log(arr.__proto__ === Array.prototype); // true
console.log(Array.prototype.hasOwnProperty('push')); // true
数组的所有方法都存在于 Array.prototype
中,所以所有数组实例都可以访问这些方法。
总结:原型与原型链要点
概念 | 描述 | 示例 |
---|---|---|
prototype |
函数特有的属性,存放共享方法 | Car.prototype.run = function(){} |
__proto__ |
对象特有的属性,指向其原型 | car.__proto__ === Car.prototype |
原型链 | 通过 __proto__ 连接的链条 |
child -> Parent.prototype -> GrandParent.prototype -> Object.prototype -> null |
属性查找 | 沿原型链向上查找属性 | child.name 查找过程 |
constructor |
指向创建对象的构造函数 | car.constructor === Car |
理解原型和原型链是掌握JavaScript面向对象编程的核心。通过原型,JavaScript实现了高效的属性共享和继承机制,这也是JavaScript区别于传统面向对象语言的重要特点。