ES6的class是函数和原型链的语法糖,本质为具名函数,挂载方法到prototype,constructor需显式调用super(),静态方法挂类本身,实例方法挂prototype,且class无变量提升、自动严格模式。

ES6 的 class 不是新对象模型,只是函数和原型链的语法糖;直接用它写类没问题,但得清楚底层仍是基于 prototype 的。
class 声明本质就是函数
你写的 class Person { },在运行时等价于一个具名函数,并自动绑定到 Person.prototype.constructor。这意味着:
-
typeof Person返回"function",不是"class" - 不能用
new.target在静态方法里判断是否被new调用(除非手动检查) - 类体中所有方法默认不可枚举(
Object.keys(Person.prototype)拿不到sayHi)
示例:
class Person {
constructor(name) {
this.name = name;
}
sayHi() {
return `Hi, ${this.name}`;
}
}
// 等价于:
// function Person(name) { this.name = name; }
// Person.prototype.sayHi = function() { return `Hi, ${this.name}`; };
constructor 和 this 绑定要注意时机
类的 constructor 必须显式调用 super()(如果继承),且必须在访问 this 前完成。否则会报 ReferenceError: Must call super constructor in derived class before accessing 'this'。
立即学习“Java免费学习笔记(深入)”;
- 没写
constructor,JS 会自动补一个空的(含隐式super()) - 写了
constructor但没写super(),哪怕只有一行console.log(1),也会立即报错 -
super()只能在子类constructor中用,且只能用一次
错误写法:
class Animal {}
class Dog extends Animal {
constructor(name) {
console.log(name); // ❌ 报错:先用了 this(隐含)再 super
super();
}
}
静态方法、实例方法、getter/setter 的区别很实在
它们挂载的位置不同,决定了谁可以调用、是否可继承、是否参与原型链查找:
-
static method()→ 挂在Dog函数本身上,Dog.method()可调,new Dog().method()报错 -
method()(无static)→ 挂在Dog.prototype上,实例可调,子类实例也继承 -
get prop()/set prop(v)→ 也是挂prototype,但行为像属性,不加括号调用
注意:static 方法中 this 指向类本身(如 Dog),而普通方法中 this 是实例。
extends 和 new.target 配合才能做真正“防误用”的类
想让一个类只能被继承、不能直接 new,光靠文档不行,得靠运行时判断。常见做法是:
- 在父类
constructor中检查new.target === ParentClass - 如果是
true,说明被直接 new 了,抛错 - 子类
new时,new.target是子类构造器,不等于父类,就放行
示例:
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('Shape is abstract and cannot be instantiated');
}
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
}
new Shape(); // ❌ Error
new Circle(5); // ✅ OK
真正容易被忽略的是:class 内部没有变量提升(ReferenceError),且严格模式自动开启(不能用 with、静默失败的赋值会报错)。这些不是“特性”,是约束——写的时候稍不留神就掉坑里。











