Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
JavaScript计算器开发:解决数值显示与初始化问题_创想鸟

JavaScript计算器开发:解决数值显示与初始化问题

javascript计算器开发:解决数值显示与初始化问题

本教程深入探讨了使用JavaScript构建计算器时常见的数值显示异常问题,特别是由于类属性未初始化导致的`Cannot read properties of undefined`错误。我们将详细分析问题根源,并通过在构造函数中调用初始化方法来解决该问题,同时优化显示逻辑,确保计算器功能稳定且界面显示准确。

引言:构建基础JavaScript计算器中的常见挑战

在Web开发中,使用HTML、CSS和JavaScript构建一个功能完备的计算器是一个经典的练习项目。然而,开发者在实现过程中常会遇到一些棘手的问题,例如点击按钮后数值无法正确显示,或者控制台报错Cannot read properties of undefined。这些问题通常源于对JavaScript类(Class)的初始化机制理解不足,以及显示逻辑处理上的疏忽。本教程将针对这些常见问题,提供一套系统的分析与解决方案,帮助您构建一个稳定可靠的计算器。

问题分析:数值未显示与undefined错误

在提供的JavaScript计算器代码中,核心功能由一个Calculator类封装。当用户尝试点击数字按钮时,期望看到相应的数字出现在显示区域。然而,实际情况是显示区域为空,并且控制台可能报告Cannot read properties of undefined (reading ‘toString’)之类的错误,尤其是在appendNumber函数内部。

让我们聚焦于appendNumber函数和Calculator类的构造函数:

立即学习“Java免费学习笔记(深入)”;

class Calculator {    constructor(previousOperandTextElement, currentOperandTextElement) {        this.previousOperandTextElement = previousOperandTextElement;        this.currentOperandTextElement = currentOperandTextElement;        // 缺少对 currentOperand 和 previousOperand 的初始化    }    appendNumber(number) {        if (number === '.' && this.currentOperand.includes('.')) return        // 问题发生在这里:如果 this.currentOperand 是 undefined,调用 toString() 会报错        this.currentOperand = this.currentOperand.toString() + number.toString()    }    // ... 其他方法}

问题根源:

this.currentOperand 未初始化: 在Calculator类的constructor方法中,虽然DOM元素被正确地赋值给了this.previousOperandTextElement和this.currentOperandTextElement,但用于存储当前和前一个操作数的内部变量this.currentOperand和this.previousOperand却未被初始化。首次调用 appendNumber: 当计算器实例创建后,用户首次点击数字按钮,appendNumber函数被调用。此时,this.currentOperand的值为undefined。尝试对undefined调用toString()方法会导致TypeError: Cannot read properties of undefined (reading ‘toString’)错误,从而阻止数值的正确追加和显示。

解决方案一:初始化类属性

解决undefined错误的关键在于确保所有在类方法中使用的核心属性在实例创建时得到初始化。Calculator类中已经有一个clear()方法,它的作用正是将currentOperand、previousOperand和operation重置为初始状态。我们可以巧妙地利用这个方法。

修复方法: 在Calculator类的constructor中调用this.clear()。

class Calculator {    constructor(previousOperandTextElement, currentOperandTextElement) {        this.previousOperandTextElement = previousOperandTextElement;        this.currentOperandTextElement = currentOperandTextElement;        this.clear(); // 关键修复:在构造函数中初始化所有操作数和操作符    }    clear() {        this.currentOperand = ''; // 初始化为空字符串        this.previousOperand = ''; // 初始化为空字符串        this.operation = undefined;    }    // ... 其他方法保持不变}

通过这一改动,当Calculator实例被创建时,this.currentOperand和this.previousOperand会立即被初始化为空字符串,从而避免了在appendNumber等方法中对undefined调用toString()的错误。

解决方案二:优化显示逻辑

除了undefined错误,原始代码在显示更新方面也存在一个常见但容易被忽视的问题,可能导致数值未能按预期格式化显示。让我们检查updateDisplay方法:

    updateDisplay() {        this.currentOperandTextElement.innerText = this.currentOperand // 直接赋值原始值            this.getDisplayNumber(this.currentOperand) // 调用格式化函数,但其返回值未被使用        if (this.operation != null) {            this.previousOperandTextElement.innerText = this.previousOperand // 直接赋值原始值                `${this.previousOperand} ${this.operation}` // 模板字符串未被使用        }        else {            this.previousOperandTextElement.innerText = ''        }    }

问题根源:

updateDisplay方法在更新显示元素时,直接将原始的this.currentOperand和this.previousOperand赋值给了innerText。紧随其后的this.getDisplayNumber()调用虽然会返回格式化后的字符串,但其返回值被丢弃了,没有被赋值给任何DOM元素。这意味着,尽管有格式化逻辑,但显示屏上看到的仍然是未经格式化的原始数值。

修复方法: 确保getDisplayNumber的返回值被正确地用于更新显示元素。

    updateDisplay() {        // 使用 getDisplayNumber 的返回值来更新当前操作数显示        this.currentOperandTextElement.innerText = this.getDisplayNumber(this.currentOperand);        if (this.operation != null) {            // 使用 getDisplayNumber 的返回值来更新前一个操作数显示,并拼接操作符            this.previousOperandTextElement.innerText = `${this.getDisplayNumber(this.previousOperand)} ${this.operation}`;        } else {            this.previousOperandTextElement.innerText = '';        }    }

通过此优化,计算器将能够正确地显示格式化后的数值,例如大数字的千位分隔符,以及精确的小数部分。

完整且修正后的JavaScript代码示例

结合上述两项修复,以下是完整的script.js代码,它解决了数值显示问题和undefined错误,并优化了显示逻辑。

class Calculator {    constructor(previousOperandTextElement, currentOperandTextElement) {        this.previousOperandTextElement = previousOperandTextElement;        this.currentOperandTextElement = currentOperandTextElement;        this.clear(); // 关键修复:在构造函数中初始化所有操作数和操作符    }    clear() {        this.currentOperand = '';        this.previousOperand = '';        this.operation = undefined;    }    delete() {        this.currentOperand = this.currentOperand.toString().slice(0, -1);    }    appendNumber(number) {        if (number === '.' && this.currentOperand.includes('.')) return;        this.currentOperand = this.currentOperand.toString() + number.toString();    }    chooseOperation(operation) {        if (this.currentOperand === '') return;        if (this.previousOperand !== '') {            this.compute();        }        this.operation = operation;        this.previousOperand = this.currentOperand;        this.currentOperand = '';    }    compute() {        let computation;        const prev = parseFloat(this.previousOperand);        const current = parseFloat(this.currentOperand);        if (isNaN(prev) || isNaN(current)) return;        switch (this.operation) {            case '+':                computation = prev + current;                break;            case '-':                computation = prev - current; // 修正:原代码为 prev + current                break;            case '*':                computation = prev * current; // 修正:原代码为 prev + current                break;            case '÷':                computation = prev / current; // 修正:原代码为 prev + current                break;            default:                return;        }        this.currentOperand = computation;        this.operation = undefined;        this.previousOperand = '';    }    getDisplayNumber(number) {        const stringNumber = number.toString();        const integerDigits = parseFloat(stringNumber.split('.')[0]);        const decimalDigits = stringNumber.split('.')[1];        let integerDisplay;        if (isNaN(integerDigits)) {            integerDisplay = '';        } else {            integerDisplay = integerDigits.toLocaleString('en', {                maximumFractionDigits: 0            });        }        if (decimalDigits != null) {            return `${integerDisplay}.${decimalDigits}`;        } else {            return integerDisplay;        }    }    updateDisplay() {        // 优化:使用 getDisplayNumber 的返回值来更新当前操作数显示        this.currentOperandTextElement.innerText = this.getDisplayNumber(this.currentOperand);        if (this.operation != null) {            // 优化:使用 getDisplayNumber 的返回值来更新前一个操作数显示,并拼接操作符            this.previousOperandTextElement.innerText = `${this.getDisplayNumber(this.previousOperand)} ${this.operation}`;        } else {            this.previousOperandTextElement.innerText = '';        }    }}const numberButtons = document.querySelectorAll('[data-number]');const operationButtons = document.querySelectorAll('[data-operation]');const equalsButton = document.querySelector('[data-equals]');const deleteButton = document.querySelector('[data-delete]');const allClearButton = document.querySelector('[data-all-clear]');const previousOperandTextElement = document.querySelector('[data-previous-operand]');const currentOperandTextElement = document.querySelector('[data-current-operand]');const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement);numberButtons.forEach(button => {    button.addEventListener('click', () => {        calculator.appendNumber(button.innerText);        calculator.updateDisplay();    });});operationButtons.forEach(button => {    button.addEventListener('click', () => {        calculator.chooseOperation(button.innerText);        calculator.updateDisplay();    });});equalsButton.addEventListener('click', button => {    calculator.compute();    calculator.updateDisplay();});allClearButton.addEventListener('click', button => {    calculator.clear();    calculator.updateDisplay();});deleteButton.addEventListener('click', button => {    calculator.delete();    calculator.updateDisplay();});

额外修正说明:在审查compute()方法时,发现加减乘除的case中,除了加法,其余运算(减、乘、除)也错误地使用了prev + current。上述完整代码已将这些逻辑错误一并修正。

注意事项与最佳实践

类属性的初始化: 始终确保在类的constructor中初始化所有关键属性,特别是那些在其他方法中会被读取或修改的属性。这可以有效避免undefined相关的运行时错误。显示逻辑的严谨性: 当涉及到数值格式化时,务必确认格式化函数的返回值被正确地应用到DOM元素上。避免调用了格式化函数但其结果却被丢弃的情况。错误处理: 对于计算器这类应用,还需要考虑更完善的错误处理,例如:除以零: 在compute方法中添加对除以零的检查。无效输入: 尽管parseFloat可以处理部分非数字输入,但更严格的输入验证可以提升健壮性。代码可读性: 保持代码结构清晰,方法职责单一,有助于后期维护和功能扩展。

总结

通过本教程,我们深入分析并解决了JavaScript计算器中常见的数值显示异常和Cannot read properties of undefined错误。核心在于理解并正确实施类属性的初始化,并通过在constructor中调用clear()方法来实现。同时,我们优化了updateDisplay方法,确保getDisplayNumber的格式化结果能够正确呈现在用户界面上。遵循这些最佳实践,将有助于您开发出更健壮、用户体验更佳的Web应用程序。

以上就是JavaScript计算器开发:解决数值显示与初始化问题的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1594227.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Tailwind CSS中实现多重盒阴影的技巧
上一篇 2025年12月23日 09:16:07
JavaScript获取DOM元素高度的常见陷阱与正确实践
下一篇 2025年12月23日 09:16:15

相关推荐

  • 设置php连接mssql的编码格式_通过php连接mssql支持UTF-8编码

    正确配置PHP连接MSSQL并支持UTF-8需:1. 使用sqlsrv扩展并启用extension=php_sqlsrv_80.dll;2. 连接时设置”CharacterSet”=>”UTF-8″;3. 数据库字段使用nvarchar等Unic…

    2026年9月22日
    100
  • 使用php连接mssql实现日志记录_通过php连接mssql完成日志管理

    使用PHP连接MSSQL可实现高效日志管理,首先需安装sqlsrv扩展并配置php.ini;接着通过sqlsrv_connect建立数据库连接,确保SQL Server启用TCP/IP协议;然后创建包含LogLevel、Message、Source等字段的AppLogs表;封装writeLog函数插…

    2026年9月22日
    000
  • laravel如何使用Pipeline模式处理复杂逻辑_Laravel Pipeline模式处理复杂逻辑方法

    Laravel Pipeline通过将复杂流程拆分为多个独立处理步骤,实现代码解耦与职责分离。以用户注册为例,可依次执行发送欢迎邮件、分配角色、记录日志等操作,每个步骤由单独类实现__invoke方法,通过Pipeline::send($user)->through([…])-&g…

    2026年9月22日
    200
  • VSCode 怎样自定义代码运行的动画效果 VSCode 代码运行动画效果的自定义方法​

    vscode本身不支持电影特效式的自定义代码运行动画,其核心设计注重功能与效率;2. 实现更生动的视觉反馈主要依赖内置机制和扩展:状态栏指示器、输出面板滚动、调试高亮等是默认反馈方式;3. 可通过安装测试运行器扩展(如jest runner、python test explorer)实现测试进度条、…

    2026年9月22日
    000
  • Swift 3到5.1新特性整理

    tocSwift 5.1Swift 5.0Result类型Raw string自定义字符串插值动态可调用类型处理未来的枚举值从try?抹平嵌套可选检查整数是否为偶数字典compactMapValues()方法撤回的功能: 带条件的计数Swift 4.2CaseIterable协议警告和错误指令动态查…

    2026年9月22日
    000
  • php-gd怎么制作缩略图_php-gd生成高质量缩略图

    使用PHP-GD生成高质量缩略图需保持宽高比、选用imagecopyresampled进行重采样,并合理设置JPEG质量(80-95),同时处理PNG透明通道,避免图像失真或背景变黑。 使用 PHP-GD 制作高质量缩略图,核心在于正确处理图像缩放、保持宽高比、避免失真,并选择合适的图像质量参数。下…

    2026年9月22日
    000
  • PHP日志记录怎么做_PHP中Monolog库实现灵活强大的日志系统

    Monolog是PHP中基于PSR-3标准的主流日志库,通过Composer安装后可轻松实现日志记录。使用Logger类创建实例并添加Handler(如StreamHandler写入文件、NativeMailerHandler邮件报警)来管理不同级别(debug、info、error等)日志输出,支…

    2026年9月22日
    200
  • PHP数组如何定义和使用_PHP数组定义与使用详细教程

    PHP数组是存储和管理多个值的核心工具,支持索引、关联、混合及多维结构;通过方括号定义,可灵活访问、修改、添加或删除元素,并利用foreach高效遍历。 PHP数组是存储一系列值的强大工具,无论这些值是简单的数据项,还是更复杂的结构。它的核心思想就是把一堆相关的数据“打包”在一起,通过一个统一的名字…

    2026年9月22日
    000
  • Java中递归处理列表:排序验证与条件性最大值移除策略

    在处理列表数据时,我们常遇到需要根据特定条件修改列表的需求。本教程将深入探讨一个具体的场景:如何设计一个递归函数,该函数首先判断一个整数列表是否已按升序排序。如果列表已排序,则停止处理;如果未排序,则进一步检查列表中的最大值。仅当最大值位于列表的起始位置或末尾时,才将其移除,并对修改后的列表重复此过…

    2026年9月22日
    000
  • PHPJSON数据怎么解析_PHP处理JSON数据格式

    PHP使用json_decode()解析JSON数据,传入字符串和true参数可转为数组,适用于API响应、文件读取等场景,需配合json_last_error()检查解析是否成功。 PHP解析JSON数据非常简单,主要依靠内置的两个函数:json_decode() 和 json_encode()。…

    2026年9月22日
    100
  • Flyway多数据库与CI/CD测试集成策略

    本文深入探讨了在CI/CD流程中,如何高效地配置Flyway以管理多数据库环境下的迁移,尤其关注集成测试场景。我们将比较使用真实数据库服务、Testcontainers以及Flyway自身多数据库配置的优劣,并提供关于分离生产与测试环境迁移脚本的实用策略,旨在确保开发、测试与生产环境的数据一致性与流…

    2026年9月22日
    100
  • PHP框架日志系统怎么记录错误_PHP框架日志系统配置指南

    PHP框架通过配置日志级别、通道和处理器,结合Monolog库实现错误记录。以Laravel和Symfony为例,可在配置文件中定义多通道(如文件、Slack)、设置不同级别(ERROR、CRITICAL),并通过门面或服务在代码中捕获异常并写入上下文信息。 PHP框架的日志系统记录错误,核心在于通…

    2026年9月22日
    000
  • 美团外卖如何使用支付宝支付

    想要在美团外卖中使用支付宝完成支付,享受更灵活便捷的点餐体验?只需几个简单步骤即可轻松实现。 首先,请确认你的手机已安装最新版本的美团外卖和支付宝应用程序。打开美团外卖App,浏览并选择你喜欢的美食,加入购物车后,点击“去结算”进入订单确认页面。 进入支付界面后,系统通常默认选择“美团支付”。此时,…

    2026年9月22日
    200
  • Spring Boot自定义Kafka配置与动态Bean注册最佳实践

    本文探讨了在Spring Boot应用中通过自定义注解简化Kafka配置的挑战与解决方案。重点介绍了如何利用META-INF/spring.factories实现早期自动配置,并详细阐述了使用ImportBeanDefinitionRegistrar在应用上下文初始化早期动态注册Kafka生产者工厂…

    2026年9月22日
    100
  • VSCode配合Vivado进行FPGA图像处理(算法加速与优化)

    答案:VSCode与Vivado结合可提升FPGA图像处理开发效率,前者用于代码编辑、版本控制和远程开发,后者负责综合、实现与调试,二者协同实现高效算法优化。 将VSCode与Vivado结合用于FPGA图像处理,本质上是利用VSCode作为高效的代码编辑、版本控制和辅助开发环境,来弥补Vivado…

    2026年9月22日
    200
  • 构建VSCode多媒体编程界面与实时音视频处理

    答案:VSCode通过配置Node.js、Python扩展及FFmpeg等工具,结合OpenCV、PyAudio等框架,可构建高效音视频处理环境。1. 安装Python和Node.js支持,启用Pylance、Jupyter插件提升数据处理体验;2. 配置终端与Code Runner实现脚本一键执行…

    2026年9月22日
    100
  • 在Java中如何开发简易问答社区

    答案是Java结合Spring Boot可快速构建问答社区,通过设计questions、answers、users三张表实现数据存储,使用JPA进行持久化,前端用HTML+JS调用后端API完成用户提问、回答、查看与互动功能。 开发一个简易问答社区,核心是实现用户提问、回答、查看问题和互动功能。Ja…

    2026年9月22日
    100
  • PHP 数组元素按日期条件过滤与删除:避免常见陷阱

    本教程详细介绍了如何在 PHP 中根据日期条件动态删除数组(或对象数组)中的元素。文章将重点讲解如何正确进行日期比较,特别是当数据源为 JSON 格式时,以及 unset 函数在遍历过程中移除元素时的正确用法,帮助开发者避免常见的字符串日期比较和对象属性访问错误。 简介 在数据处理中,根据特定条件过…

    2026年9月22日
    100
  • linux系统下codeblocks控制台打印中文乱码[通俗易懂]

    linux系统下codeblocks控制台打印中文乱码[通俗易懂]linux系统下codeblocks控制台打印中文乱码[通俗易懂]linux系统下codeblocks控制台打印中文乱码[通俗易懂]linux系统下codeblocks控制台打印中文乱码[通俗易懂]

    大家好,很高兴再次和大家见面,我是你们的朋友全栈君。 在Linux系统下使用CodeBlocks时,如果在控制台中打印中文可能会遇到乱码问题。以下是解决这一问题的详细步骤: 首先,我们来看一下在Linux系统下安装CodeBlocks后,运行以下代码时出现的问题: #include #include…

    2026年9月22日 用户投稿
    600
  • 解决Android设备管理移除时的SecurityException

    本文将详细介绍如何解决在尝试从Android设备移除设备管理员时遇到的java.lang.SecurityException异常。该异常通常发生在尝试移除一个非测试用途的设备管理员应用时。通过修改应用的配置,将其临时标记为测试应用,可以绕过此安全限制,从而成功移除设备管理员。请务必注意,这种方法仅适…

    2026年9月22日
    100

发表回复

登录后才能评论
关注微信