本文由一缘原创整理,系统梳理 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 等原生方法