【问题标题】:Random value not in the range of array/dictionary随机值不在数组/字典范围内
【发布时间】:2021-05-14 18:19:55
【问题描述】:

我这周刚开始学习 Javascript 来编写一个文字游戏来帮助我的孩子。这个想法是它应该显示和播放来自dictionaryrandom 单词,她写道,entry 被选中,random 被从dictionary 中删除。游戏一直持续到字典length===0,有错字就总结。不知何故,该程序是不可预测的,它实际上是七分之一的工作,我不明白为什么。给出以下错误:

Uncaught (in promise) TypeError: Cannot read property 'word' of undefined

我确实认为这与我删除random 的方式有关,或者检查dictonary 是否为空。代码下方粘贴了指向 console.log 屏幕截图的链接; 1 是程序完全完成的结果,另一个是没有完成的结果。有趣的是,错误也是不可预知的,有时只是 1 个字,有时是 2 个字。我唯一要做的就是刷新页面,程序的行为会有所不同。我也尝试在不同的浏览器上运行它。

作为一个菜鸟,我很惊讶我在尝试做同样的事情时得到了不同的结果。发现发生了什么非常令人沮丧:-)

<html>
<head>
    <title>Aliyah's dictee spel</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="header">
    <h1>Hej! Velkommen til Aliyahs diktee!</h1>
    </div>
    <div id="Random_word">
        <h2 id="Empty">Click start to start</h2>
        <button id="startGame">Start</button>
        <button id="editList">Edit word list</button>
        <h3 id="correctWord"></h3>

    </div>
    <script>
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    var dictionary = [
        {   word: "apple",
            audio: 'apple.mp3',
        },
        {
            word: "baby",
            audio: 'baby.mp3',
        },
        {
            word: "car",
            audio: 'car.mp3'
        }

    ];

    var wordsWrong = [];
    var wordsCorrectCounter = 0;
    var wordsWrongCounter = 0;
    //var cheer = new Audio('correct.mp3');
    //var boo = new Audio('wrong.mp3');

    function editWords(){
        console.log("under construction");
    };

    function startGame(){
        document.getElementById("startGame").remove();
        document.getElementById("editList").remove();
        newWord(dictionary);
    };
    
    async function newWord(dictionary)
    {
        if (Object.entries(dictionary).length === 0){
            endGame();
        }
            else {
                var random = Math.floor(Math.random() * dictionary.length);
                document.getElementById("Empty").innerHTML = dictionary[random].word;
                console.log(dictionary[random].word);
                console.log(dictionary);
                await sleep(2000);
                document.getElementById("Empty").innerHTML = "       ";
                createInputField(random);
            }
    };

    function createInputField(random)
    {
        var entry = document.createElement("input");
        entry.setAttribute("type", "text");
        entry.id = "inputfield";
        document.body.appendChild(entry);
        let btn = document.createElement("button");
        btn.id = "okBtn";
        btn.innerHTML = "ok";
        btn.type = "submit";
        btn.name = "answerBtn";
        document.body.appendChild(btn);
        document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random, entry.value));
    };

    function checkAnswer(random, entry)
        {var answer = entry.toLowerCase();
    
        if (dictionary[random].word == answer){
            //cheer.play();
            wordsCorrectCounter += 1;
            document.getElementById("okBtn").remove();
            document.getElementById("inputfield").remove();
            delete dictionary[random];
            console.log(dictionary);
            newWord(dictionary);
        }
            else{
                wordsWrong.push(dictionary[random].word);
                wordsWrongCounter += 1;
                document.getElementById("okBtn").remove();
                document.getElementById("inputfield").remove();
                //boo.play();
                document.body.style.backgroundColor = "red";
                document.getElementById("correctWord").innerHTML = dictionary[random].word;
                let btn = document.createElement("button");
                btn.id = "contBtn";
                btn.innerHTML = "Continue";
                btn.type = "submit";
                btn.name = "continueBtn";
                document.body.appendChild(btn);
                document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random));
            }
    };

    function wrongAnswer(random){
        document.getElementById("contBtn").remove();
        document.getElementById("correctWord").innerHTML = "    "
        delete dictionary[random];
        newWord(dictionary);
    };

    function endGame()
    {
        document.getElementById("Empty").innerHTML = "you are done!" + "Correct: " + wordsCorrectCounter + "Wrong: " + wordsWrongCounter 
        + "These words were wrong: " + wordsWrong;
        

    };

    function Refresh() {
        window.parent.location = window.parent.location.href;
    };
 
    document.getElementById("startGame").addEventListener("click", () => startGame());



    

    </script>
</body>
</html>

Console.log when program is able to finish

Console.log when program gets stuck

【问题讨论】:

  • 表示你的随机值不在你的数组范围内
  • 比随机更简单的事情就是在开始时对数组进行洗牌并读取第一个索引并将其删除。
  • 考虑编辑您的问题以将控制台日志显示为文本而不是图像。如果你这样做了,我会给你一个向上的箭头。
  • 感谢您的反馈。我考虑过,但它看起来不像打印屏幕那样对读者友好,而且似乎没有任何好处,因为你不需要复制/粘贴它。好吧,至少我是这么认为的。但我下次一定会的!

标签: javascript google-chrome dictionary random


【解决方案1】:

简短解释

dictionary = [
    { word: "apple", audio: 'apple.mp3', },
    { word: "baby", audio: 'baby.mp3', },
    { word: "car", audio: 'car.mp3' }
];

你生成一个随机索引,比如说2
您可以直接使用 2 并通过 dictionary[2].word 提取单词

如果你通过了随机索引
在您从字典中删除项目
之后,它可能是无效 这就是你得到错误的原因

例如:
你有 old 随机索引 2
但是您已经删除了该项目
当前字典是

dictionary = [
    { word: "apple", audio: 'apple.mp3', },
    { word: "baby", audio: 'baby.mp3', },
];

然后你尝试访问dictionary[2]
已经不存在了

从数组中删除项目

你可以使用Array.filter()

let dictionary = [
    { word: "apple", audio: 'apple.mp3', },
    { word: "baby", audio: 'baby.mp3', },
    { word: "car", audio: 'car.mp3' }
];
// only the item that item.word != "apple" will pass this
dictionary = dictionary.filter(item => item.word != "apple");

console.log(dictionary);

字符串和变量

Template literals (Template strings)
使用它来设置字符串,它更具可读性和更易于编辑
您可以使用${variable_name} 将变量放入其中

示例:

let x = "test";
console.log(`this is a ${x}`);

在数组中查找特定项

我看到你有音频文件
如果您需要在字典中查找项目
您可以使用Array.find()
因为我们现在只传字
我们可以用它来找到它
假设您要查找 apple 的音频
会是这样的

let dictionary = [
            { word: "apple", audio: 'apple.mp3', },
            { word: "baby", audio: 'baby.mp3', },
            { word: "car", audio: 'car.mp3' }
        ],
    target = dictionary.find(item => item.word=="apple"),
    audio = false;
if(target) audio = target.audio;
console.log(audio);

完整答案

我已经添加评论了,你可以查看一下

<html>

<head>
    <title>Aliyah's dictee spel</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
    <div id="header">
        <h1>Hej! Velkommen til Aliyahs diktee!</h1>
    </div>
    <div id="Random_word">
        <h2 id="Empty">Click start to start</h2>
        <button id="startGame">Start</button>
        <button id="editList">Edit word list</button>
        <h3 id="correctWord"></h3>

    </div>
    <script>
        function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        var dictionary = [
            { word: "apple", audio: 'apple.mp3', },
            { word: "baby", audio: 'baby.mp3', },
            { word: "car", audio: 'car.mp3' }
        ];

        var wordsWrong = [];
        var wordsCorrectCounter = 0;
        var wordsWrongCounter = 0;
        //var cheer = new Audio('correct.mp3');
        //var boo = new Audio('wrong.mp3');

        function editWords() {
            console.log("under construction");
        }

        function startGame() {
            document.getElementById("startGame").remove();
            document.getElementById("editList").remove();
            newWord();
        }

        // dictionary is global variable, you don't need to pass it to access it
        async function newWord() {

            // I add this so the color will be reset after click continue
            document.body.style.backgroundColor = "";

            if (Object.entries(dictionary).length === 0) {
                endGame();
            } else {
                var random = Math.floor(Math.random() * dictionary.length),
                    // get the random word here when it still exist in dictionary
                    random_word = dictionary[random].word;

                document.getElementById("Empty").innerHTML = random_word;
                console.log(random_word);
                console.log(dictionary);
                await sleep(2000);
                document.getElementById("Empty").innerHTML = "       ";

                // direct pass the ramdom word, not the ramdom index
                // ramdom index could be invalid after you remove item from dictionary
                // which is why you get the error
                createInputField(random_word);
            }
        }

        function createInputField(random_word) {
            var entry = document.createElement("input");
            entry.setAttribute("type", "text");
            entry.id = "inputfield";
            document.body.appendChild(entry);
            let btn = document.createElement("button");
            btn.id = "okBtn";
            btn.innerHTML = "ok";
            btn.type = "submit";
            btn.name = "answerBtn";
            document.body.appendChild(btn);
            document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random_word, entry.value));
        }

        function checkAnswer(random_word, entry) {
            var answer = entry.toLowerCase();

            if (random_word == answer) {
                //cheer.play();

                // if you only need +1, you can use ++
                wordsCorrectCounter++;

                document.getElementById("okBtn").remove();
                document.getElementById("inputfield").remove();

                // use Array.filter() to remove random_word(answer) from the dictionary
                // only word != random_word will pass
                dictionary = dictionary.filter(item => item.word != random_word);
                console.log(dictionary);
                newWord();
            } else {
                // I didn't see this, so I add it
                // if you only need +1, you can use ++
                wordsWrongCounter++;

                // because we pass the random_word(answer) now, we can just push it
                wordsWrong.push(random_word);

                document.getElementById("okBtn").remove();
                document.getElementById("inputfield").remove();
                //boo.play();
                document.body.style.backgroundColor = "red";
                document.getElementById("correctWord").innerHTML = random_word;
                
                let btn = document.createElement("button");
                btn.id = "contBtn";
                btn.innerHTML = "Continue";
                btn.type = "submit";
                btn.name = "continueBtn";
                document.body.appendChild(btn);

                document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random_word));
            }
        }

        function wrongAnswer(random_word) {
            document.getElementById("contBtn").remove();
            document.getElementById("correctWord").innerHTML = "    ";
            // same as above
            // use Array.filter() to remove correct_word(answer) from the dictionary
            // only word != correct_word will pass
            dictionary = dictionary.filter(item => item.word != random_word);
            newWord();
        }

        function endGame() {
            /*
            use `` to set string, it more readable & easier to edit
            you can put variable in it by use ${variable_name}

            example: 
            let x = "test";
            console.log(`this is a ${x}`);
            
            result:
            this is a test
            */
            document.getElementById("Empty").innerHTML =
                `you are done! Correct: ${wordsCorrectCounter} Wrong: ${wordsWrongCounter} These words were wrong: ${wordsWrong}`;
        }

        function Refresh() {
            window.parent.location = window.parent.location.href;
        }

        document.getElementById("startGame").addEventListener("click", () => startGame());
    </script>
</body>

</html>

【讨论】:

  • 谢谢!这是非常有见地的!中间的额外反馈也非常有帮助。我不太了解音频位,但我使用了 '''var audio = new Audio(dictionary[random].audio); audio.play()''' 它可以工作,但如果这不是正确的方式,我愿意接受建议:-) 再次感谢!
【解决方案2】:

我刚刚在您的代码中遇到了问题,这有点概念性的东西,没什么。

See what's going wrong in this screenshot of console

您可以看到删除单词(对象)后字典(数组)的长度仍然相同。 因为您使用了:delete 关键字,它删除一个项目并用empty 替换它,并且数组的大小保持不变。
因此删除第一个单词后的新字典变成:[empty, {...}, {...}] 现在,每当您尝试获取 dictionary[0].word 都会给您一个错误:无法读取 undefine 的属性,因为它是空的

您可以简单地使用dictionary.splice(random, 1),而不是使用delete 关键字

See the console screenshot after using splice

<html>
<head>
    <title>Aliyah's dictee spel</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <div id="header">
    <h1>Hej! Velkommen til Aliyahs diktee!</h1>
  </div>
  <div id="Random_word">
    <h2 id="Empty">Click start to start</h2>
    <button id="startGame">Start</button>
    <button id="editList">Edit word list</button>
    <h3 id="correctWord"></h3>

  </div>
  <script>
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    var dictionary = [{
        word: "apple",
        audio: 'apple.mp3',
      },
      {
        word: "baby",
        audio: 'baby.mp3',
      },
      {
        word: "car",
        audio: 'car.mp3'
      }

    ];

    var wordsWrong = [];
    var wordsCorrectCounter = 0;
    var wordsWrongCounter = 0;
    var cheer = new Audio('correct.mp3');
    var boo = new Audio('wrong.mp3');

    function editWords() {
      console.log("under construction");
    };

    function startGame() {
      document.getElementById("startGame").remove();
      document.getElementById("editList").remove();
      newWord(dictionary);
    };

    async function newWord(dictionary) {
      if (Object.entries(dictionary).length === 0) {
        endGame();
      } else {
        var random = Math.floor(Math.random() * dictionary.length);
        console.log(random)
        document.getElementById("Empty").innerHTML = dictionary[random].word;
        console.log(dictionary[random].word);
        console.log(dictionary);
        await sleep(2000);
        document.getElementById("Empty").innerHTML = "       ";
        createInputField(random);
      }
    };

    function createInputField(random) {
      var entry = document.createElement("input");
      entry.setAttribute("type", "text");
      entry.id = "inputfield";
      document.body.appendChild(entry);
      let btn = document.createElement("button");
      btn.id = "okBtn";
      btn.innerHTML = "ok";
      btn.type = "submit";
      btn.name = "answerBtn";
      document.body.appendChild(btn);
      document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random, entry.value));
    };

    function checkAnswer(random, entry) {
      var answer = entry.toLowerCase();

      if (dictionary[random].word == answer) {
        cheer.play();
        wordsCorrectCounter += 1;
        document.getElementById("okBtn").remove();
        document.getElementById("inputfield").remove();
        dictionary.splice(random, 1);
        console.log(dictionary);
        newWord(dictionary);
      } else {
        wordsWrong.push(dictionary[random].word);
        wordsWrongCounter += 1;
        document.getElementById("okBtn").remove();
        document.getElementById("inputfield").remove();
        boo.play();
        document.body.style.backgroundColor = "red";
        document.getElementById("correctWord").innerHTML = dictionary[random].word;
        let btn = document.createElement("button");
        btn.id = "contBtn";
        btn.innerHTML = "Continue";
        btn.type = "submit";
        btn.name = "continueBtn";
        document.body.appendChild(btn);
        document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random));
      }
    };

    function wrongAnswer(random) {
      document.getElementById("contBtn").remove();
      document.getElementById("correctWord").innerHTML = "    "
      delete dictionary[random];
      newWord(dictionary);
    };

    function endGame() {
      document.getElementById("Empty").innerHTML = "you are done!" + "Correct: " + wordsCorrectCounter + "Wrong: " + wordsWrongCounter +
        "These words were wrong: " + wordsWrong;


    };

    function Refresh() {
      window.parent.location = window.parent.location.href;
    };

    document.getElementById("startGame").addEventListener("click", () => startGame());
  </script>
</body>

</html>

【讨论】:

  • 我确实尝试过这种方法,但不知何故我也遇到了麻烦。使用 filter.array() 代替了我的窍门。谢谢!
猜你喜欢
  • 2016-07-01
  • 2015-06-21
  • 1970-01-01
  • 2019-08-31
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
相关资源
最近更新 更多