当前位置: 首页 > news >正文

深入解析:ES6 中 class 与普通构造器的区别

前言背景

在 JavaScript 的发展历程中,类的实现方式经历了从构造函数到 ES6 class 的演变。

很多开发者认为 class 只是构造函数的语法糖,但实际上两者在细节上存在诸多差异。

本文将从语法形式、内部机制、使用限制等多个维度,深入剖析 class 与普通构造器的区别。

从一道面试题说起

先看一道经典面试题:如何将以下 ES6 class 代码转换为等效的 ES5 实现?

class Example { constructor(name) { this.name = name;}init() { const fun = () => { console.log(this.name) }fun(); } 
}
const e = new Example('Hello');
e.init(); // 输出:Hello

要解答这道题,我们需要先理解 class 与构造函数的本质区别。让我们从两者的基本写法开始对比。

基本写法对比

ES6 class 写法

ES6 引入了 class 关键字,使类的定义更加简洁清晰:

class Computer {// 构造器constructor(name, price) {this.name = name;this.price = price;}// 原型方法showSth() {console.log(`这是一台${this.name}电脑`);}// 静态方法static comStruct() {console.log("电脑由显示器,主机,键鼠组成");}
}

使用方式:

const apple = new Computer("苹果", 15000);
console.log(apple.name); // 苹果
apple.showSth(); // 这是一台苹果电脑
Computer.comStruct(); // 电脑由显示器,主机,键鼠组成

ES5 构造函数写法

在 ES6 之前,我们通过构造函数模拟类的实现:

function Computer(name, price){this.name = name;this.price = price;
}
// 原型方法
Computer.prototype.showSth = function(){console.log(`这是一台${this.name}电脑`);
}
// 静态方法
Computer.comStruct = function(){console.log("电脑由显示器,主机,键鼠组成");
}

使用方式与 class 完全一致:

const apple = new Computer("苹果", 15000);
console.log(apple.name); // 苹果
apple.showSth(); // 这是一台苹果电脑
Computer.comStruct(); // 电脑由显示器,主机,键鼠组成

从表面看,两种写法实现了相同的功能,但深入细节会发现它们存在本质区别。

核心区别解析

1. 调用方式限制

普通构造函数本质是函数,既可以用new调用,也可以直接调用:

// 普通构造函数
function Computer2() {}// 直接调用(不会报错)
const i = Computer2();
console.log(i); // undefined

而 class 必须使用new调用,直接调用会报错:

// ES6 class
class Computer1 {}// 直接调用(报错)
Computer1(); 
// TypeError: Class constructor Computer1 cannot be invoked without 'new'

这是因为 class 内部做了调用方式检查,确保只能通过实例化方式使用。

2. 原型方法的可枚举性

普通构造函数的原型方法默认是可枚举的:

const apple = new Computer2("苹果", 15000);
for(var i in apple){console.log(i); 
}
// 输出:
// name
// price
// showSth

class 的原型方法默认是不可枚举的:

const huawei = new Computer1("华为", 12000);
for(var i in huawei){console.log(i); 
}
// 输出:
// name
// price

这种差异会影响对象遍历的结果,在某些场景下(如对象拷贝)需要特别注意。

3. 严格模式

class 内部默认运行在严格模式下,而普通构造函数默认在非严格模式下运行:

// class中定义重复参数(报错)
class Computer1 {showSth(i,i) { // SyntaxError: Duplicate parameter name not allowed in this contextconsole.log(`这是一台${this.name}电脑`);}
}// 普通构造函数中定义重复参数(不报错)
Computer2.prototype.showSth = function(j,j){console.log(`这是一台${this.name}电脑`);
}

严格模式带来了更多的语法限制,如禁止重复参数、禁止未声明变量赋值等,有助于编写更规范的代码。

4. 原型方法的构造器限制

普通构造函数的原型方法可以作为构造函数使用(通过 new 调用):

const apple = new Computer2("苹果", 15000);
const i = new apple.showSth(); // 可以执行
console.log(i); // {}

class 的原型方法不能作为构造函数使用:

const huawei = new Computer1("华为", 12000);
const i = new huawei.showSth(); 
// TypeError: huawei.showSth is not a constructor

Babel 转译揭示的本质

通过 Babel 将 class 转译为 ES5 代码,可以更清晰地看到 class 的内部实现机制:

"use strict";
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}
}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor)descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}
}function _createClass(Constructor, protoProps, staticProps) {if (protoProps)_defineProperties(Constructor.prototype, protoProps);if (staticProps)_defineProperties(Constructor, staticProps);return Constructor;
}var Computer = /*#__PURE__*/function () {function Computer(name, price) {_classCallCheck(this, Computer);this.name = name;this.price = price;}_createClass(Computer, [{key: "showSth",value: function showSth() {console.log(`这是一台${this.name}电脑`);}}], [{key: "comStruct",value: function comStruct() {console.log("电脑由显示器,主机,键鼠组成");}}]);return Computer;
}();

转译后的代码揭示了几个关键函数的作用:

  1. _classCallCheck:检查调用方式,确保只能通过 new 实例化
  2. _defineProperties:定义属性时设置描述符(控制可枚举性等)
  3. _createClass:将原型方法和静态方法挂载到对应位置

这些函数共同实现了 class 的特殊行为,使其与普通构造函数区分开来。

面试题解答

回到开头的面试题,将 ES6 class 转换为 ES5 的关键在于:

  • 实现 class 的调用检查
  • 正确处理原型方法的可枚举性
  • 处理箭头函数的 this 绑定(箭头函数会捕获当前上下文的 this)

完整的 ES5 实现:

"use strict";function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}
}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor)descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}
}function _createClass(Constructor, protoProps, staticProps) {if (protoProps)_defineProperties(Constructor.prototype, protoProps);if (staticProps)_defineProperties(Constructor, staticProps);return Constructor;
}var Example = /*#__PURE__*/function () {function Example(name) {_classCallCheck(this, Example);this.name = name;}_createClass(Example, [{key: "init",value: function init() {var _this = this; // 保存this引用,模拟箭头函数的this绑定var fun = function fun() {console.log(_this.name);};fun();}}]);return Example;
}();var e = new Example('Hello');
e.init(); // 输出:Hello

总结

class 虽然在表面上看起来是构造函数的语法糖,但实际上:

  1. class 有更严格的调用限制(必须使用 new)
  2. class 的原型方法默认不可枚举
  3. class 内部自动启用严格模式
  4. class 的原型方法不能作为构造函数使用
  5. class 提供了更清晰的语法结构和继承机制

理解这些差异有助于我们在实际开发中选择合适的方式,并避免因误解而产生的 bug。在现代 JavaScript 开发中,推荐使用 class 语法,它不仅使代码更具可读性,也能通过严格模式和语法限制帮助我们编写更健壮的代码。


文章转载自:

http://AenRrok1.cwgfq.cn
http://YUPp6Mln.cwgfq.cn
http://1cdWdlNS.cwgfq.cn
http://6xCq75Zy.cwgfq.cn
http://eiETd2Gw.cwgfq.cn
http://1pcQoVY6.cwgfq.cn
http://neGmmsdD.cwgfq.cn
http://i16XughI.cwgfq.cn
http://re2C4zuI.cwgfq.cn
http://Xk4gd1OH.cwgfq.cn
http://02T8BQ8t.cwgfq.cn
http://oGazs2N0.cwgfq.cn
http://vhi3EgHH.cwgfq.cn
http://lpzVOxU7.cwgfq.cn
http://InjYjcsI.cwgfq.cn
http://iQUrbTS8.cwgfq.cn
http://zkgCUxOJ.cwgfq.cn
http://TXs3rnYz.cwgfq.cn
http://Wor2CHBv.cwgfq.cn
http://FIRZIC1L.cwgfq.cn
http://WNi4FnEL.cwgfq.cn
http://Lv4E05AU.cwgfq.cn
http://P5XtzfUb.cwgfq.cn
http://zuh0V19a.cwgfq.cn
http://xDQ7QIHq.cwgfq.cn
http://MIfquScY.cwgfq.cn
http://VAYIFWRq.cwgfq.cn
http://FpXzOESe.cwgfq.cn
http://8pY1aAW0.cwgfq.cn
http://XFhsXpGR.cwgfq.cn
http://www.dtcms.com/a/377412.html

相关文章:

  • 华清远见25072班网络编程学习day3
  • QT(3)
  • 具有区域引导参考和基础的大型语言模型,用于生成 CT 报告
  • 【QT】-怎么实现瀑布图
  • 【Leetcode hot 100】94.二叉树的中序遍历
  • 渗透测试真的能发现系统漏洞吗
  • 【芯片设计-信号完整性 SI 学习 1.2 -- loopback 回环测试】
  • Android App瘦身方法介绍
  • MySQL修改字段类型避坑指南:如何应对数据截断与转换错误?
  • Linux权限以及常用热键集合
  • 成品油加油站综合监管迈入 “云时代”!智慧物联网涉税数据采集平台推行工作全面推进
  • c primer plus 第五章复习题和练习题
  • C++设计模式,高级开发,算法原理实战,系统设计与实战(视频教程)
  • Spring 统一功能处理
  • ES6基础入门教程(80问答)
  • 第3讲 机器学习入门指南
  • InnoDB 逻辑存储结构:好似 “小区管理” 得层级结构
  • copyparty 是一款使用单个 Python 文件实现的内网文件共享工具,具有跨平台、低资源占用等特点,适合需要本地化文件管理的场景
  • C# 哈希查找算法实操
  • 一个C#开发的Windows驱动程序管理工具!
  • 环境变量
  • Codeforces Round 1049 (Div. 2)
  • Eclipse下载安装图文教程(非常详细,适合新手)
  • vue2迁移到vite[保姆级教程]
  • 基于webpack的场景解决
  • Vite 中的 import.meta.env 与通用 process.env.NODE_ENV 的区别与最佳实践
  • 除了Webpack,还有哪些构建工具可以实现不同环境使用不同API地址?
  • sklearn聚类
  • I.MX6UL:汇编LED驱动实验
  • 计算机毕设 java 高校机房综合管控系统 基于 SSM+Vue 的高校机房管理平台 Java+MySQL 的设备与预约全流程系统