3、JavaScript 到底需不需要“类”?你可能被误导了多年

112 阅读2分钟

在前端江湖里,流传着一句话:
👉 “JavaScript 没有类,所以要想办法模拟类!”

于是,早期无数前端苦哈哈地写过这种“伪 OOP”代码:

function Animal(name) {
  this.name = name;
}
Animal.prototype.say = function() {
  console.log(this.name + " makes a noise.");
};

但问题是:我们真的需要模拟类吗?


1. 模拟类的历史根源

JavaScript 一开始就不是为“类继承”而设计的。

  • Brendan Eich 本来想做一个 基于原型的语言
  • 但因为管理层要求“像 Java”,于是硬塞了 newthis
  • 结果就是:JS 看起来像 Java,却没有完整的“类”体系(继承不完善)。

于是,社区涌现了各种模拟方案:PrototypeJS、Dojo、无数框架互不兼容。一片混乱。


2. 原型:JS 的真正灵魂

如果抛开“类”的执念,JS 的原型系统其实非常优雅。
两条规则足矣:

  1. 每个对象都有一个私有字段 [[prototype]]
  2. 访问属性时,如果本对象没有,就顺着原型链继续查找。

举个例子:

var cat = {
  say() { console.log("meow~"); }
};

var tiger = Object.create(cat, {
  say: {
    value: function() { console.log("roar!"); }
  }
});

tiger.say(); // roar!

不用类、不用继承,原型就能搞定抽象与复用。


3. new 背后的真相

很多人以为 new 是“创造类的语法”。错!
它的底层逻辑其实是:

  1. 以构造器的 prototype 为原型,创建一个新对象;
  2. 执行构造器,把 this 绑定到新对象;
  3. 如果构造器返回对象,就用它;否则用步骤 1 的对象。

所以,new 只是个“语法糖”,帮函数变装成“类”的样子。


4. ES6 class:语法糖的正规化

直到 ES6,JS 才终于有了官方的 class

class Animal {
  constructor(name) { this.name = name; }
  speak() { console.log(this.name + " makes a noise."); }
}

class Dog extends Animal {
  speak() { console.log(this.name + " barks."); }
}

new Dog("Mitzie").speak(); // Mitzie barks.

注意:运行时还是原型系统!
class 只是让代码更清晰、更不容易写出奇怪的 bug。


5. 我们真的需要“类”吗?

答案是:看场景。

  • 如果你追求 直观、团队协作、继承关系 → 用 class,语义清晰,坑更少;
  • 如果你追求 灵活、运行时动态扩展、函数式风格 → 直接用原型,别再死守类的幻觉。

JS 的强大之处在于:它两条路都能走,关键在于你是否理解其运行时本质。


写在最后

JavaScript 从来不是“没有类”,而是它选择了 原型作为核心
ES6 的 class 让写法统一,但背后仍然是 prototype。

所以,下次再有人说“JS 不是面向对象语言”,你就可以告诉他:
👉 JS 是 OOP,只不过是 prototype 风格的 OOP。

互动问题
👉 你现在写项目更常用 class,还是依旧坚持用函数+原型?为什么?
欢迎在评论区留言,一起碰撞思路!