JavaScript代码调用getAttribute()报错:无法读取undefined的属性
计算器按键点击功能报错排查
错误原因分析
1. 闭包变量作用域问题
你用var声明循环变量i,var的作用域是函数级,循环结束后i的值会变成point.length(超出按钮数组的索引范围)。当点击按钮触发事件回调时,point[i]已经是undefined,所以调用getAttribute会抛出TypeError。
2. 显示屏内容拼接逻辑错误
当前代码里display.innerHTML += display.innerHTML + value会重复拼接现有内容,比如初始显示为空时,第一次点击数字1会变成undefinedundefined1;如果初始有值,比如显示0,点击1会变成001,完全不符合计算器的正常显示逻辑。
修正后的代码
const display = document.getElementById("calculator_display"); const buttons = document.getElementsByClassName("calc_button"); let operand1 = 0; let operand2 = null; let operator = null; // 用let声明循环变量,形成块级作用域 for (let i = 0; i < buttons.length; i++) { buttons[i].addEventListener("click", function() { // 用this获取当前点击的按钮元素,彻底规避闭包变量问题 const value = this.getAttribute("data-value"); if (value === "+") { operator = "+"; operand1 = parseFloat(display.textContent); // 点击运算符后清空显示屏,准备输入第二个操作数 display.textContent = ""; } else if (value === "=") { operand2 = parseFloat(display.textContent); // 替换eval为安全的运算判断,避免代码注入风险 let ans; switch(operator) { case "+": ans = operand1 + operand2; break; // 后续可扩展其他运算符逻辑 } display.textContent = ans; // 运算完成后重置状态,方便下一次计算 operand1 = 0; operand2 = null; operator = null; } else { // 正常追加数字/小数点到显示屏 display.textContent += value; } }); }
关键修改点说明
- 把
var替换为let声明循环变量i,形成块级作用域,每个循环迭代的i都是独立的,避免闭包导致的索引溢出问题。 - 用
this在事件回调中直接获取当前点击的按钮元素,无需依赖循环变量,彻底解决point[i]为undefined的问题。 - 修改显示屏拼接逻辑为
display.textContent += value,保证内容正常追加,符合计算器的交互习惯。 - 替换风险较高的
eval为switch条件判断执行运算,避免恶意代码注入的安全问题。 - 增加运算符点击后清空显示屏、运算后重置状态的逻辑,贴合真实计算器的使用流程。
内容的提问来源于stack exchange,提问作者Aman Ahmed
相关产品推荐
相关产品推荐

