Appearance
JavaScript 原型与原型链深度解析
原型系统核心概念
原型定义
- 函数对象:所有函数都有
prototype
属性(显式原型) - 实例对象:所有对象都有
__proto__
属性(隐式原型),指向其构造函数的prototype
- 特殊关系:
- 函数的实例对象没有
prototype
属性 Object.prototype
是所有对象的原型终点
- 函数的实例对象没有
原型链形成机制
- 对象访问属性时,先在自身属性中查找
- 若未找到,通过
__proto__
向上层原型查找 - 递归执行此过程,直到找到属性或到达原型链顶端(
null
)
javascript
function Person() {}
Person.prototype.say = function () {
return "Hello";
};
const person = new Person();
console.log(person.say()); // "Hello"(来自原型)
关键原型指向关系
表达式 | 值 | 说明 |
---|---|---|
Object.prototype.__proto__ | null | 原型链终点 |
Function.prototype === Function.__proto__ | true | 特殊自引用关系 |
Object.__proto__ === Function.prototype | true | Object 是 Function 的实例 |
Array.__proto__ === Function.prototype | true | 数组构造函数继承自 Function |
对象与函数创建原理
对象创建
javascript
// 字面量创建(推荐)
const obj1 = {};
// 构造函数创建
const obj2 = new Object();
// 原型关系验证
console.log(obj1.__proto__ === Object.prototype); // true
console.log(obj2.__proto__ === Object.prototype); // true
函数创建
javascript
// 函数声明
function fn() {}
// 构造函数创建
const fn2 = new Function();
// 原型关系验证
console.log(fn.__proto__ === Function.prototype); // true
console.log(fn2.__proto__ === Function.prototype); // true
constructor 属性
核心特性
- 实例对象本身没有
constructor
属性 - 访问时从原型链查找,最终指向构造函数
javascript
function Person() {}
const p = new Person();
console.log(p.constructor === Person); // true
console.log(Person.prototype.constructor === Person); // true
// 内置对象验证
console.log([].constructor === Array); // true
console.log({}.constructor === Object); // true
原型链核心优势
共享数据:减少内存占用
javascriptfunction Person() {} Person.prototype.species = "Human"; const p1 = new Person(); const p2 = new Person(); // 共享species属性,不占用实例内存
实现继承:建立对象间继承关系
类型检测机制
instanceof 原理
- 检测左操作数是否在右操作数的原型链上
- 递归检查
left.__proto__ === right.prototype
javascript
function Animal() {}
function Dog() {}
Dog.prototype = new Animal();
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true
安全检测问题
javascript
// 未声明变量检测
typeof undeclaredVar; // 'undefined'(安全)
undeclaredVar instanceof Object; // ReferenceError(危险)
实现 instanceof
javascript
function myInstanceof(left, right) {
// 基本类型直接返回false
if (left === null || typeof left !== "object") return false;
let proto = left.__proto__;
const prototype = right.prototype;
while (true) {
if (proto === null) return false;
if (proto === prototype) return true;
proto = proto.__proto__;
}
}
原型属性检测
hasOwnProperty
- 检测属性是否属于对象自身(非原型链)
- 不查找原型链
javascript
const obj = { name: "John" };
console.log(obj.hasOwnProperty("name")); // true
console.log(obj.hasOwnProperty("toString")); // false(来自原型)
核心方法实现
new 操作符实现
javascript
function myNew(Constructor, ...args) {
// 1. 创建新对象并链接原型
const obj = Object.create(Constructor.prototype);
// 2. 执行构造函数并绑定this
const result = Constructor.apply(obj, args);
// 3. 处理返回值
return result instanceof Object ? result : obj;
}
// 使用示例
function Person(name) {
this.name = name;
}
const p = myNew(Person, "Alice");
console.log(p.name); // 'Alice'
Object.create 实现
javascript
Object.myCreate = function (proto) {
function F() {} // 中介构造函数
F.prototype = proto; // 设置原型
return new F(); // 返回实例
};
// 使用示例
const base = { type: "object" };
const obj = Object.myCreate(base);
console.log(obj.type); // 'object'
console.log(obj.__proto__ === base); // true
继承实现方案
1. 构造继承(经典继承)
特点:
- 继承父类实例属性
- 无法继承原型方法
javascript
function Parent(name) {
this.name = name;
this.colors = ["red"];
}
function Child(name) {
Parent.call(this, name); // 调用父类构造函数
}
const c1 = new Child("Tom");
c1.colors.push("blue");
console.log(c1.colors); // ['red', 'blue']
const c2 = new Child("Jerry");
console.log(c2.colors); // ['red'](独立实例)
2. 原型继承
特点:
- 共享原型属性
- 实例间相互影响
javascript
function Parent() {
this.nums = [1, 2];
}
function Child() {}
Child.prototype = new Parent(); // 设置原型
const c1 = new Child();
c1.nums.push(3);
const c2 = new Child();
console.log(c2.nums); // [1, 2, 3](共享问题)
3. 组合继承(推荐)
特点:
- 结合构造和原型继承优点
- 实例属性独立,原型方法共享
javascript
function Parent(name) {
this.name = name;
this.colors = ["red"];
}
Parent.prototype.sayName = function () {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承实例属性
this.age = age;
}
// 继承原型方法
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // 修复constructor
const c1 = new Child("Tom", 10);
c1.colors.push("blue");
const c2 = new Child("Jerry", 8);
console.log(c1.colors); // ['red', 'blue']
console.log(c2.colors); // ['red'](独立)
c1.sayName(); // 'Tom'(共享方法)
4. 多继承实现
javascript
function extend(target, ...sources) {
sources.forEach((source) => {
// 复制实例属性
Object.getOwnPropertyNames(source.prototype).forEach((prop) => {
if (prop !== "constructor") {
target.prototype[prop] = source.prototype[prop];
}
});
});
return target;
}
// 使用示例
function Flyer() {}
Flyer.prototype.fly = function () {
console.log("Flying");
};
function Swimmer() {}
Swimmer.prototype.swim = function () {
console.log("Swimming");
};
function SuperHero() {}
extend(SuperHero, Flyer, Swimmer);
const hero = new SuperHero();
hero.fly(); // 'Flying'
hero.swim(); // 'Swimming'
最佳实践建议
- 优先使用组合继承:平衡性能和功能需求
- 避免修改内置原型:防止命名冲突
- 使用
Object.create
设置原型:比直接赋值更安全 - 始终修复 constructor:保持正确的构造函数指向
- 现代替代方案:考虑 ES6 的
class
和extends
语法