JavaScript ES6 class构造函数标准写法示例
全面讲解 JavaScript ES6 class 构造函数(constructor)的标准写法、传参与默认值、属性绑定、继承场景下的 super() 规则及常见避坑指南。
constructor(构造函数)。本文将直接给出构造函数的标准语法定义、参数处理与属性赋值模式,剖析继承场景下 super() 的关键调用逻辑与常见避坑规则。
1. ES6 class 构造函数的基本语法
在 ES6 之前,JavaScript 使用常规函数结合原型链(prototype)模拟类行为。ES6 则通过 class 关键字将对象的构造过程标准化。每个类内部有且仅能声明一个名为 constructor 的方法,在通过 new 运算符生成新实例时,该方法会自动执行。
// 基础标准写法
class User {
constructor(name, email) {
// 1. 初始化实例属性
this.name = name;
this.email = email;
this.createdAt = new Date();
}
// 原型方法,供所有实例共享
getInfo() {
return `${this.name} (${this.email})`;
}
}
// 实例化调用
const user1 = new User('张三', 'zhangsan@example.com');
console.log(user1.getInfo());
// 示例输出: 张三 (zhangsan@example.com)
当执行 new User(...) 时,JavaScript 引擎会经历固定阶段:开辟内存并创建空对象、将空对象的原型指向 User.prototype、将内部的 this 绑定到该空对象、执行 constructor 内部逻辑完成赋值,最后返回该对象。
2. 参数解构、默认值与防御性编写
在实际项目开发中,构造函数往往需要接受多个配置参数。如果直接按位置传入过多入参,会导致代码可读性降低,且不利于后续扩展。工程上推荐结合 ES6 的参数解构与默认参数语法进行编写。
// 带有配置项解构与默认值的标准写法
class HttpClient {
constructor({
baseURL = 'https://api.example.com',
timeout = 5000,
headers = {},
retryCount = 3
} = {}) { // 默认为空对象,防止未传参时报 TypeError
this.baseURL = baseURL;
this.timeout = timeout;
this.headers = {
'Content-Type': 'application/json',
...headers
};
this.retryCount = retryCount;
}
}
// 灵活的实例化方式
const clientA = new HttpClient(); // 全部使用默认值
const clientB = new HttpClient({
timeout: 10000,
headers: { 'Authorization': 'Bearer token_123' }
});
console.log(clientB.timeout); // 示例输出: 10000
console.log(clientB.retryCount); // 示例输出: 3
上述代码中末尾的 = {} 是关键的防御性设计。若不写 = {},在调用 new HttpClient()(未传参)时,解构引擎会尝试对 undefined 执行解构,直接抛出 TypeError: Cannot destructure property ... of undefined。
3. 继承与派生类中的 super() 调用规范
当使用 extends 关键字实现类的继承时,子类的 constructor 具有特殊的执行机制。在派生类构造函数中,必须在访问 this 之前调用 super()。
// 父类定义
class BaseComponent {
constructor(id, tag = 'div') {
this.id = id;
this.tag = tag;
}
render() {
return `<${this.tag} id="${this.id}"></${this.tag}>`;
}
}
// 子类继承
class ButtonComponent extends BaseComponent {
constructor(id, label, variant = 'primary') {
// 必须首先调用 super(),并将必要参数传递给父类构造函数
super(id, 'button');
// 只有在 super() 执行后,this 才能安全访问
this.label = label;
this.variant = variant;
}
render() {
return `<button id="${this.id}" class="btn-${this.variant}">${this.label}</button>`;
}
}
const submitBtn = new ButtonComponent('btn-submit', '确认提交');
console.log(submitBtn.render());
// 示例输出: <button id="btn-submit" class="btn-primary">确认提交</button>
this,再通过 Parent.call(this) 修饰。而在 ES6 中正好相反:派生类的 this 是通过父类构造函数创建的,调用 super() 就是在执行父类构造函数并初始化基类实例,随后将其包装绑定给子类的 this。因此,如果在 super() 之前引用 this,会直接抛出 ReferenceError: Must call super constructor in derived class before accessing 'this'。
4. 常见写法误区与关键限制
编写 ES6 类构造函数时,开发者容易受到旧有语法习惯或误解影响,以下四个关键限制是日常排错的重点:
| 场景 | 错误写法 / 行为 | 正确规范 | 影响后果 |
|---|---|---|---|
| 重复声明 | 在同一个 class 内写两个 constructor | 只保留唯一的 constructor 方法 | 报 SyntaxError: A class may only have one constructor |
| 函数式调用 | 直接调用 User('张三') |
必须通过 new User('张三') 调用 |
报 TypeError: Class constructor cannot be invoked without 'new' |
| 返回值控制 | 在 constructor 内部显式 return 123 |
不写 return,默认返回 this |
返回基本类型会被完全忽略;若返回对象则会替换 this |
| 继承顺序 | 在 super() 前书写 this.x = 1 |
super() 必须置于首行或访问 this 之前 |
报 ReferenceError: Must call super... |
4.1 构造函数返回值陷阱
默认情况下,constructor 不需要写 return 语句,解释器会自动返回新构建的 this。若显式写入返回值:
- 如果返回的是基本数据类型(如
number、string、boolean、null、undefined),该返回值会被完全忽略,外部依然获得正常的实例对象。 - 如果返回的是一个新对象(如
return { a: 1 }),则new运算符会放弃原本初始化的this,将该新对象直接交付给调用方。这通常属于反模式,极易引发难以排查的 Bug。
5. 总结
ES6 class 的 constructor 规范确立了统一、直观的对象初始化标准。在日常编码中,遵循“使用对象解构提供默认值”、“派生类严格先调用 super()”、“避免任何显式非 this 返回”的规范,能够有效避免绝大部分运行时错误,并让面向对象代码保持高度可读与可维护性。
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58








![JS输出对象显示[object Object]怎么办?JSON.stringify格式化打印技巧](https://img.javascript.cn/tit/articles/13236/20261105/6eaec9baed78171fe0bc2b74184ba5b7b80ebd52de7d3323ff152268aa2df294.webp)