JavaScript中class是原型链的语法糖,本质仍是基于[[Prototype]]的委托继承:构造函数定义类、prototype挂载共享方法、extends实现原型链连接、属性查找遵循实例→原型→Object.prototype→null的链式规则。

JavaScript 本身没有原生的“类”结构,它的面向对象能力是靠原型链模拟出来的。ES6 的 class 只是语法糖,背后仍是原型机制在运行。要理解它怎么“像类”,关键在于看清三件事:如何定义共享行为、如何建立继承关系、以及属性和方法如何被查找和复用。
构造函数 + prototype 模拟“类定义”
在 class 出现之前,开发者用函数作为“类模板”,通过 prototype 挂载所有实例共享的方法:
- 每个函数自动拥有
prototype属性,指向一个默认对象 - 这个
prototype对象会成为所有new出来的实例的隐式原型(即__proto__) - 把方法写在
prototype上,就能让多个实例共用同一份代码,节省内存
例如:function Person(name) { this.name = name; } 定义“类”,Person.prototype.sayHi = function() { console.log('Hi, ' + this.name); }; 就相当于给“类”加了一个公共方法。
原型链实现“继承”效果
子“类”要复用父“类”的方法,不是复制代码,而是让自己的原型指向父类的实例或原型:
立即学习“Java免费学习笔记(深入)”;
-
Child.prototype = Object.create(Parent.prototype)是推荐做法:新建一个空对象,其__proto__指向Parent.prototype - 这样
new Child()实例访问方法时,查不到自身就顺着原型链找到Parent.prototype,再往上到Object.prototype,最后到null - 还需手动修复
constructor,否则child.constructor会指向Parent
这整个链条——实例 → 子构造函数 prototype → 父构造函数 prototype → Object.prototype → null——就是 JavaScript 的继承路径。
class 关键字只是包装,不改变底层逻辑
写 class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a sound'); } } 看起来很像 Java,但编译后仍是基于原型的操作:
-
Animal.prototype.speak依然存在,且所有实例的__proto__都指向它 -
extends本质是执行了类似Child.prototype = Object.create(Parent.prototype)的操作 -
super()在构造函数里,实际调用的是Parent.call(this, ...),完成属性初始化
也就是说,你写的 class 会被引擎翻译成原型链操作,而不是创建新类型的“类对象”。
属性查找规则支撑整个机制
真正让这套模拟“类”的方式跑起来的,是 JavaScript 的属性动态查找规则:
- 读取属性时,先查实例自身(自有属性)
- 没找到就查
__proto__指向的对象(即构造函数的prototype) - 还没找到就继续查那个对象的
__proto__,一层层向上,直到Object.prototype或null - 写入属性时,默认只写在当前实例上,不会意外修改原型上的值
这个机制让方法复用、继承、多态都自然发生,不需要编译期类型检查或虚拟表(vtable)支持。


















