
文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本篇技术指南围绕现代 JavaScript 教程The Modern JavaScript Tutorial中「数组方法」章节的经典练习「创建一个可扩展的 calculator」展开完整解析Calculator构造函数的参考实现与测试用例帮助你掌握如何用「字符串拆分 一元正号转换 方法注册表」实现一个可插拔的算术运算引擎。学完后你将能够自己写出支持加减乘除乃至求幂运算的可扩展计算器并理解「面向未来的扩展点」在小型项目中的设计思路。练习背景与任务拆解本练习位于 数组方法章节 的课后任务中对应 任务描述属于 JavaScript 基础到进阶过渡阶段的典型「构造函数 方法注册表」训练题。任务要求创建构造函数Calculator产出「可扩展」的计算器对象分为两个阶段基础能力实现calculate(str)方法接受格式为「数字 运算符 数字」以空格分隔的字符串并返回结果至少理解加号与减号-let calc new Calculator; alert( calc.calculate(3 7) ); // 10扩展能力实现addMethod(name, func)方法为计算器注册新运算name是运算符func(a, b)是接收两个参数并返回结果的函数let powerCalc new Calculator; powerCalc.addMethod(*, (a, b) a * b); powerCalc.addMethod(/, (a, b) a / b); powerCalc.addMethod(**, (a, b) a ** b); let result powerCalc.calculate(2 ** 3); alert( result ); // 8任务约束明确没有括号或复杂表达式数字与运算符之间只有一个空格错误处理可自行选择是否实现。参考实现插件式运算的注册表设计仓库给出了完整的参考实现位于 solution.jsfunction Calculator() { this.methods { -: (a, b) a - b, : (a, b) a b }; this.calculate function(str) { let split str.split( ), a split[0], op split[1], b split[2]; if (!this.methods[op] || isNaN(a) || isNaN(b)) { return NaN; } return this.methodsop; }; this.addMethod function(name, func) { this.methods[name] func; }; }整个实现只有三个关键组成部分逐一拆解如下。1. 方法注册表this.methods构造函数内部通过this.methods { -: ..., : ... }维护一个对象形式的运算注册表。这里的关键设计是运算能力不写在calculate的if/else分支里而是以运算符字符串为键、以双参数函数为值集中存储。内置的加法和减法作为初始注册项与将来通过addMethod注册的运算在地位上完全平等——这正是参考解答注释solution.md强调的要点「请注意方法的存储方式。它们只是被添加到this.methods属性中。」2. 解析与执行calculate(str)calculate方法内部依次完成三步let split str.split( ), // 按空格拆分 a split[0], // 一元正号转换为数字 op split[1], // 运算符字符串 b split[2];split( )把3 7拆成[3, , 7]三个片段这与任务「数字和运算符之间只有一个空格」的约束严格对应因此按单个空格切分即可稳定工作split[0]与split[2]使用一元正号运算符把字符串强制转换为数字。相比Number()或parseInt写法更简洁且对3、7这类纯数字字符串转换结果准确随后通过this.methods[op]以运算符为键查表命中则调用对应函数并返回this.methodsop。3. 防御性校验返回 NaN 而非抛错if (!this.methods[op] || isNaN(a) || isNaN(b)) { return NaN; }两个维度的守卫运算符不存在!this.methods[op]覆盖了op未注册、op为undefined字符串片段不足等场景数字转换失败isNaN(a) || isNaN(b)拦截了非数字输入例如把abc传入。任一条件成立即返回NaN用「哨兵值」表示非法输入而不是抛出异常打断流程。由于参考实现主动选择了这条路径任务中「错误处理可自行选择」的开放项在这里的答案是返回 NaN 作为统一的失败信号。4. 扩展入口addMethod(name, func)this.addMethod function(name, func) { this.methods[name] func; };向注册表写入新键值对即可完成扩展代码本身极简。乘法*、除法/、求幂**这类新运算本质上是把对应的二元函数普通函数或箭头函数挂到methods表上powerCalc.addMethod(*, (a, b) a * b); powerCalc.addMethod(/, (a, b) a / b); powerCalc.addMethod(**, (a, b) a ** b);注意**是 ES2016 引入的幂运算符2 ** 3结果为 8由于运算符以字符串形式存储多字符运算符如**与单字符运算符在注册表中一视同仁只需保证字符串拆分时它作为一个整体片段被切分出来。测试用例四则运算与幂运算的行为验证仓库同时提供了针对该实现的单元测试 test.js采用 Mocha 的 BDD 风格编写可以逐条验证上述行为describe(Calculator, function() { let calculator; before(function() { calculator new Calculator; }); it(calculate(12 34) 46, function() { assert.equal(calculator.calculate(12 34), 46); }); it(calculate(34 - 12) 22, function() { assert.equal(calculator.calculate(34 - 12), 22); }); it(add multiplication: calculate(2 * 3) 6, function() { calculator.addMethod(*, (a, b) a * b); assert.equal(calculator.calculate(2 * 3), 6); }); it(add power: calculate(2 ** 3) 8, function() { calculator.addMethod(**, (a, b) a ** b); assert.equal(calculator.calculate(2 ** 3), 8); }); });测试覆盖了两个层次内置运算加法12 34与减法34 - 12验证calculate的字符串解析与查表执行链路动态扩展先addMethod注册乘法与幂运算再调用calculate(2 * 3)与calculate(2 ** 3)验证扩展后计算器能立刻使用新运算且2 ** 3 8符合幂运算语义。这组测试也印证了注册表设计的可测试性不需要为每个新运算改写calculate的内部逻辑只需注册、调用、断言三步即可完成新能力的验收。设计要点总结为什么把「判断」集中到calculate参考解答在 solution.md 中给出了两条核心设计结论也是本题最值得吸收的编程思想方法即数据存储在this.methods属性中。运算能力被当作可枚举、可增删的数据看待而不是写死的代码分支。新增运算的成本从「修改calculate内部」降为「往表里加一条记录」符合开闭原则对扩展开放、对修改关闭的朴素实践。所有检测和数字转换都通过calculate完成。即解析字符串、转数字、校验运算符是否注册、调用对应函数这些横切关注点统一收敛在calculate这一个入口里。将来如果要把计算器扩展为支持更复杂的表达式例如多运算符、括号、优先级只需要增强calculate的解析与执行逻辑注册表this.methods本身无需改动——参考解答明确提到「将来可能会扩展它以支持更复杂的表达式」这正是把校验集中化的动机。从整体结构看这个练习是「构造函数 对象方法 一元正号转换 对象查表」的综合性训练new Calculator生成独立实例各实例的methods相互隔离互不污染箭头函数作为一等公民被存入对象属性字符串解析配合类型转换完成输入处理。理解这一小段代码等于掌握了在 JavaScript 中构建「可插拔能力」的最小可行模式。延伸思考注册表模式在真实代码中的应用虽然本题的场景是玩具级计算器但this.methods这种「名称 → 处理函数」的注册表模式在真实项目中非常常见命令分发器按命令字符串查表路由到对应处理器替代长长的switch/case表单验证器按字段名注册校验规则函数插件系统第三方插件通过类似addMethod的 API 向核心注册能力核心对插件一无所知只负责查表调用。当calculate需要升级为支持复杂表达式时你还可以结合 数组方法章节 中学到的split、map、reduce等工具重构解析流程让this.methods注册表继续作为运算的单一数据源。这也正是本教程把该练习安排在数组方法章节末尾的用意先用数组方法武装自己再用它们去构造更灵活的程序结构。相关资源任务描述见 task.md参考实现见 solution.js配套测试见 test.js。建议先独立完成编码再对照参考实现与测试用例验证自己的设计。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐Modern JavaScript Tutorial 实战用构造器函数打造可扩展的 Calculator 计算器Modern JavaScript Tutorial 实战用构造器函数打造可扩展的 Calculator 计算器 本篇技术指南以 Modern JavaScr文档/教程前端用构造函数实现 Calculator 计算器JavaScript 构造器模式实战演练用构造函数实现 Calculator 计算器JavaScript 构造器模式实战演练 导读 本文围绕 Modern JavaScript Tutorial h文档/教程前端en.javascript.info 实战任务解析用构造函数打造可扩展计算器Extendable Calculatoren.javascript.info 实战任务解析用构造函数打造可扩展计算器Extendable Calculator 导读 本篇基于现代 JavaScr文档/教程前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考