深入理解 JavaScript 原型链与继承机制
本文由一缘原创整理,系统梳理 JS 原型链与继承机制的本质、常见用法、易错点与最佳实践,配合代码和输出,适合所有前端开发者。
深入理解 JavaScript 原型链与继承机制
原型链和继承是 JS 面试和实战的高频考点,也是理解对象、类、OOP 的基础。
1. 原型与原型链的本质
- 每个对象都有
__proto__
指向其原型对象 - 构造函数有
prototype
属性,实例的__proto__
指向构造函数的prototype
- 原型链是对象属性查找的链路
function Foo() {}
const f = new Foo();
console.log(f.__proto__ === Foo.prototype); // true
console.log(Foo.prototype.constructor === Foo); // true
console.log(Object.getPrototypeOf(f) === Foo.prototype); // true
输出:
true
true
true
2. 属性查找与原型链
- JS 查找属性时,先查自身,再查原型链,直到 Object.prototype
const obj = { a: 1 };
console.log(obj.toString); // 来自 Object.prototype
输出:
[Function: toString]
3. 手写 new 操作符
function myNew(Constructor, ...args) {
const obj = {};
obj.__proto__ = Constructor.prototype;
const result = Constructor.apply(obj, args);
return typeof result === 'object' && result !== null ? result : obj;
}
function Person(name) { this.name = name; }
const p = myNew(Person, 'Tom');
console.log(p.name);
输出:
Tom
4. 手写 instanceof 操作符
function myInstanceof(obj, Constructor) {
let proto = Object.getPrototypeOf(obj);
while (proto) {
if (proto === Constructor.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
function Foo() {}
const f = new Foo();
console.log(myInstanceof(f, Foo));
console.log(myInstanceof(f, Object));
输出:
true
true
5. ES5 原型继承实现
function Animal(name) {
this.name = name;
}
Animal.prototype.say = function() {
console.log('I am ' + this.name);
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
const d = new Dog('旺财');
d.say();
输出:
I am 旺财
6. ES6 class 继承
class Animal {
constructor(name) {
this.name = name;
}
say() {
console.log('I am ' + this.name);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
const d = new Dog('小黑');
d.say();
输出:
I am 小黑
7. 原型链继承的陷阱
- 引用类型属性会被所有实例共享
function Parent() {
this.arr = [];
}
Parent.prototype.push = function(val) { this.arr.push(val); };
function Child() {}
Child.prototype = new Parent();
const c1 = new Child();
const c2 = new Child();
c1.push(1);
c2.push(2);
console.log(c1.arr, c2.arr);
输出:
[1, 2] [1, 2]
8. 组合继承与寄生组合继承
- 组合继承:构造函数继承 + 原型继承
- 寄生组合继承:只继承一次原型,最优方案
function Parent(name) { this.name = name; }
Parent.prototype.say = function() { console.log(this.name); };
function Child(name) { Parent.call(this, name); }
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const c = new Child('组合继承');
c.say();
输出:
组合继承
9. Object.create 的原理
- 创建一个新对象,原型指向参数对象
const proto = { x: 1 };
const obj = Object.create(proto);
console.log(obj.x);
输出:
1
10. 总结与最佳实践
- 理解原型链是 JS OOP 的基础
- 推荐用 ES6 class 语法,避免手写原型继承陷阱
- 多用 Object.create、Object.setPrototypeOf 等原生方法