在前端江湖里,流传着一句话:
👉 “JavaScript 没有类,所以要想办法模拟类!”
于是,早期无数前端苦哈哈地写过这种“伪 OOP”代码:
function Animal(name) {
this.name = name;
}
Animal.prototype.say = function() {
console.log(this.name + " makes a noise.");
};
但问题是:我们真的需要模拟类吗?
1. 模拟类的历史根源
JavaScript 一开始就不是为“类继承”而设计的。
- Brendan Eich 本来想做一个 基于原型的语言;
- 但因为管理层要求“像 Java”,于是硬塞了
new、this; - 结果就是:JS 看起来像 Java,却没有完整的“类”体系(继承不完善)。
于是,社区涌现了各种模拟方案:PrototypeJS、Dojo、无数框架互不兼容。一片混乱。
2. 原型:JS 的真正灵魂
如果抛开“类”的执念,JS 的原型系统其实非常优雅。
两条规则足矣:
- 每个对象都有一个私有字段
[[prototype]]; - 访问属性时,如果本对象没有,就顺着原型链继续查找。
举个例子:
var cat = {
say() { console.log("meow~"); }
};
var tiger = Object.create(cat, {
say: {
value: function() { console.log("roar!"); }
}
});
tiger.say(); // roar!
不用类、不用继承,原型就能搞定抽象与复用。
3. new 背后的真相
很多人以为 new 是“创造类的语法”。错!
它的底层逻辑其实是:
- 以构造器的
prototype为原型,创建一个新对象; - 执行构造器,把
this绑定到新对象; - 如果构造器返回对象,就用它;否则用步骤 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,还是依旧坚持用函数+原型?为什么?
欢迎在评论区留言,一起碰撞思路!