JavaScript原型链全面解析
点赞收藏防丢失,关注不迷路!爱你们,蟹蟹!😘
1. 属性(Property)
定义
属性就是对象上的键值对。键可以是字符串或 Symbol,值可以是任意类型。
分为 自有属性(own property) 和 继承属性(来自原型链)。
作用
用来描述对象的数据和行为(方法也是属性,值为函数)。
支撑对象的数据存储和访问。
实际开发场景
保存数据状态:
user.name = 'Tom'
。保存行为:
user.login = function(){...}
。判断属性归属:
const obj = {a:1};
console.log(obj.hasOwnProperty('a')); // true,自有属性
console.log('toString' in obj); // true,来自原型链
2.原型(Prototype)
定义
在 JavaScript 中,“原型”是指对象之间用来实现继承的机制。
每个对象都可以通过内部属性
[[Prototype]]
(即“对象的原型”)指向另一个对象,这个对象就是它的原型。
作用
提供一种 共享属性和方法 的方式,避免每个对象都存一份。
实现 JavaScript 的继承体系。
实际开发场景
构造函数创建实例时,把通用方法写到
prototype
上,让所有实例共享。
function Person(name) {this.name = name;
}
Person.prototype.sayHi = function() {return 'Hi, I am ' + this.name;
};const p1 = new Person('Tom');
const p2 = new Person('Jerry');
console.log(p1.sayHi === p2.sayHi); // true,共享方法
3. 原型对象(Prototype Object)
定义
每一个构造函数都有一个属性 prototype,它指向一个对象,这个对象称为“原型对象”。
这个原型对象中可以存放所有实例共享的方法和属性
作用
节省内存:不需要为每个对象都单独定义方法,所有实例共享同一个方法。
提供
constructor
属性(默认指回构造函数)。
实际开发场景
自定义类时,方法写在原型对象上:
function Car(brand) { this.brand = brand; }
Car.prototype.run = function(){ console.log(this.brand + ' is running'); };
const c = new Car('BMW');
c.run(); // BMW is running
4. 对象的原型(Object’s [[Prototype]])
定义
对象的内部属性
[[Prototype]]
,可以通过Object.getPrototypeOf(obj)
或obj.__proto__
访问。指向另一个对象,形成链条。
指向:person.__proto__ === Person.prototype // true
是实例对象的原型指针,它指向构造函数的 prototype 属性
注意:__proto__ 是浏览器里的非标准属性,标准语法是 Object.getPrototypeOf(person)
作用
用于属性查找:当访问对象属性时,如果自身没有,就会去对象的原型上找。
实际开发场景
判断继承关系:
function A(){}
const a = new A();
console.log(Object.getPrototypeOf(a) === A.prototype); // true
修改原型(谨慎):
const obj = {};
Object.setPrototypeOf(obj, { greet(){console.log('hi')} });
obj.greet(); // hi
5. Object.prototype
定义
所有普通对象原型链的顶端对象。
Object.prototype.__proto__ === null
。
作用
提供所有对象都能用的通用方法:
toString()
、valueOf()
、hasOwnProperty()
等。
实际开发场景
自定义
toString
,实现对象的字符串化:
const user = {name:'Tom'};
console.log(user.toString()); // [object Object]
利用
hasOwnProperty
区分自有属性和继承属性。
6. constructor
定义
每个原型对象默认有一个
constructor
属性,指向对应的构造函数。如:
Person.prototype.constructor === Person
。
作用
提供从实例反查构造函数的一种方式。
帮助识别实例的构造函数(不可靠,可以被改写)。
实际开发场景
某些库/框架用
obj.constructor
来恢复对象:
function Person(name){ this.name=name; }
const p = new Person('Tom');
console.log(p.constructor === Person); // true
但是注意:如果你覆盖了
prototype
,要手动修复constructor
。
7. 原型链(Prototype Chain)
是什么?
是由一系列对象的 [[Prototype]]
(__proto__
)指针连接起来的链式结构。JavaScript 通过这个链实现继承和属性查找。
定义
对象通过
[[Prototype]]
链接起来,形成链条。属性查找会沿着链条向上,直到
null
为止。
作用
实现继承(方法、属性共享)。
是 JavaScript 面向对象编程的核心机制。
实际开发场景
类继承ES5(基于原型链的类继承):
function Animal(){}// 相当于定义一个类 Animal.prototype.eat = function(){ console.log('eating'); };//类的方法function Dog(){} Dog.prototype = Object.create(Animal.prototype); // 继承 Dog.prototype.bark = function(){ console.log('woof'); };const d = new Dog(); d.eat(); // 继承自 Animal d.bark(); // 自己的
类继承:指一个类继承另一个类的属性和方法,比如在 ES6之后用
class
+extends
:
class Animal {eat() { console.log('eating'); }
}
class Dog extends Animal {bark() { console.log('woof'); }
}
const d = new Dog();
d.eat(); // 继承自 Animal
d.bark(); // Dog 自己的方法
原型继承(prototype inheritance)
// 场景:ES5 实现继承
function Parent() {this.parentProperty = true;
}
Parent.prototype.parentMethod = function() {};function Child() {this.childProperty = false;
}
// 关键:让 Child 的原型指向 Parent 的实例,从而建立原型链
Child.prototype = new Parent();const childInstance = new Child();
console.log(childInstance.parentProperty); // true,通过原型链继承而来
console.log(childInstance instanceof Parent); // true// 场景:扩展内置对象(不推荐在生产环境使用)
Array.prototype.myCustomSum = function() {return this.reduce((acc, val) => acc + val, 0);
};
const arr = [1, 2, 3];
console.log(arr.myCustomSum()); // 6
框架源码中大量使用:比如 Vue 2 的组件实例,就是基于原型链继承来的。
8. 它们的联系
函数.prototype(原型对象)
⬇
实例的 [[Prototype]](对象的原型 / 对象原型)
⬇
Object.prototype(顶层原型对象)
⬇
null(原型链的终点)属性 是对象存储数据/行为的基本单元。
constructor 只是原型对象上的一个属性,默认指向构造函数。
原型链 串联起对象和它们的原型对象,使属性查找和继承得以实现。
✅ 总结一句话:
属性是对象的数据/方法;
原型对象存放构造函数实例共享的方法;
对象的原型 / 对象原型是实例内部指向原型对象的引用;
Object.prototype是所有普通对象继承的最终原型;
constructor是原型对象上指向构造函数的属性;
原型链是这些对象通过
[[Prototype]]
串起来的继承体系。