HTML页面中JavaScript函数间的变量共享方案咨询
你现在通过隐藏DOM元素传递变量的做法确实不够优雅,而且完全没必要——我们有几种纯JavaScript的方案可以解决这个问题,既不用依赖DOM存储变量,也不会因重复执行wordSet导致单词重置。
为什么你之前的全局变量尝试失败?
你提到用全局变量时得到了[Object object],这大概率是因为你错误地把DOM元素本身赋值给了变量,而不是它的内容。比如如果写了var word = document.getElementById("checkword")而不是word = document.getElementById("checkword").innerHTML,就会得到一个DOM对象,打印出来就是[object HTMLParagraphElement]。正确的做法是直接把随机生成的单词存在变量里,不用经过DOM中转。
方案1:正确使用全局变量(最简单)
在全局作用域声明一个变量来存储当前单词,直接在wordSet里赋值,check函数直接读取这个变量即可:
修改后的核心代码
// 在script最顶部声明全局变量,专门存储当前要猜的单词 let currentWord; function wordRand(){ var words = ["DOG", "CAT", "MOUSE", "GIRAFFE"]; return words[Math.floor(Math.random()*words.length)]; } function replaceAt(str,index,chr){ if(index > str.length-1) return str; return str.substring(0,index) + chr + str.substring(index+1); } function wordSet(){ var i; currentWord = wordRand(); // 直接把随机生成的单词赋值给全局变量 // 注意这里用=而不是+=,避免页面刷新后重复拼接内容 document.getElementById("text").innerHTML = currentWord.charAt(0); for(i=1;i<currentWord.length;i++){ document.getElementById("text").innerHTML += '-'; } // 删掉之前存单词的隐藏元素相关代码 } function check(letter){ var exists=false, i, correct; // 直接使用全局变量currentWord,不用从DOM读取 for(i=1;i<currentWord.length;i++){ if(currentWord.charAt(i)==letter){ exists=true; correct = document.getElementById("text").innerHTML; correct = replaceAt(correct, i, letter); document.getElementById("text").innerHTML = correct; } } if(!exists){ document.getElementById("verify").innerHTML += "No "; } }
方案2:闭包封装(更优雅,避免全局污染)
如果不想污染全局作用域(避免和其他脚本变量冲突),可以把所有游戏逻辑封装在一个自执行闭包里,变量只在闭包内部可见,同时把需要在HTML中调用的函数暴露到全局:
完整修改后的代码
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <script type="text/javascript"> // 自执行闭包,封装所有游戏逻辑,避免全局变量污染 (function() { let currentWord; // 闭包内的私有变量,外部无法访问 function wordRand(){ var words = ["DOG", "CAT", "MOUSE", "GIRAFFE"]; return words[Math.floor(Math.random()*words.length)]; } function replaceAt(str,index,chr){ if(index > str.length-1) return str; return str.substring(0,index) + chr + str.substring(index+1); } function wordSet(){ var i; currentWord = wordRand(); document.getElementById("text").innerHTML = currentWord.charAt(0); for(i=1;i<currentWord.length;i++){ document.getElementById("text").innerHTML += '-'; } } function check(letter){ var exists=false, i, correct; for(i=1;i<currentWord.length;i++){ if(currentWord.charAt(i)==letter){ exists=true; correct = document.getElementById("text").innerHTML; correct = replaceAt(correct, i, letter); document.getElementById("text").innerHTML = correct; } } if(!exists){ document.getElementById("verify").innerHTML += "No "; } } // 把需要在HTML中调用的函数暴露到全局,让onclick能访问 window.wordSet = wordSet; window.check = check; })(); </script> </head> <body onload="wordSet();"> <p id="text"></p> <p id="verify">Mistakes: </p> <div id="keyboard"> <button onclick="check('Q');">Q</button> <button onclick="check('W');">W</button> <button onclick="check('E');">E</button> <button onclick="check('R');">R</button> <button onclick="check('T');">T</button> <button onclick="check('Y');">Y</button> <button onclick="check('U');">U</button> <button onclick="check('I');">I</button> <button onclick="check('O');">O</button> <button onclick="check('P');">P</button> <button onclick="check('A');">A</button> <button onclick="check('S');">S</button> <button onclick="check('D');">D</button> <button onclick="check('F');">F</button> <button onclick="check('G');">G</button> <button onclick="check('H');">H</button> <button onclick="check('J');">J</button> <button onclick="check('K');">K</button> <button onclick="check('L');">L</button> <button onclick="check('Z');">Z</button> <button onclick="check('X');">X</button> <button onclick="check('C');">C</button> <button onclick="check('V');">V</button> <button onclick="check('B');">B</button> <button onclick="check('N');">N</button> <button onclick="check('M');">M</button> </div> <!-- 删掉这个用于存单词的隐藏p元素 --> </body> </html>
这个方案的好处是currentWord不会暴露到全局,避免了变量冲突的风险,是更专业的JavaScript写法。
方案3:DOM自定义属性(备选)
如果不想用全局变量或闭包,还可以把单词存在DOM元素的自定义data-*属性里,比如:
在wordSet函数里添加:
document.getElementById("text").dataset.currentWord = currentWord;
然后在check函数里读取:
const currentWord = document.getElementById("text").dataset.currentWord;
这种方法不用额外变量,但还是依赖DOM,不过比隐藏元素更干净。
不管选哪种方案,都能解决你现在的问题,不用再依赖隐藏的DOM元素来传递变量了。
内容的提问来源于stack exchange,提问作者user15613304

