来自函数 Javascript 的 NaN 返回值 ||函数执行顺序

NaN return value from function Javascript || Function Execution Order

本文关键字:函数 顺序 执行 返回值 Javascript NaN      更新时间:2023-09-26
这里的

Javascript新手,经过几个小时挖掘其他问题,老实说,我不太确定如何解释这一点,但我会尽力而为,希望你能帮助我。

.HTML:

<div id='header'> <h1> Pastel Land </h1> </div>
    <div id='container'>
        <div id='readyContainer'> 
            <h3> This game will start in </h3>
            <h1 id='readySeconds'> </h1>
        </div>
        <div id='shape'> </div>
    </div>
    <div id='features'>
        <button id='start'> START </button> 
        <button id='stop'> STOP </button>
        <p id='timeBox'></p>
        <p id='timeAverageBox'></p>
    </div>
    <div id='testbox'> </div>

完整脚本:

document.getElementById('start').onclick = function () { 
        document.getElementById('readyContainer').style.display = 'block';
        document.getElementById('readySeconds').innerHTML = '3'
        setTimeout(function() {document.getElementById('readySeconds').innerHTML = '2'}, 1000);
        setTimeout(function() {document.getElementById('readySeconds').innerHTML = '1'}, 2000);

        setTimeout(readyAlert,3000);
        setTimeout(displayShape, 3000);

        var style = document.getElementById('shape').style;
        var el = document.getElementById('shape');
        el.addEventListener("click", a, false);
        el.addEventListener("click", b, false);
        function a() {
            style.display = "none";
            displayShapeDelay(); // calls the delay function
        }
        function b() { 
            end = new Date().getTime();  // saves time when clicked
            var time = (end - start)/1000 ; // calculates interval from shape creation until click
            document.getElementById('timeBox').innerHTML = time + 's';
            return time;
        }
        document.getElementById('testbox').innerHTML = b();

        function readyAlert() {
                document.getElementById('readyContainer').style.display = 'none';
        }   
        function getRandomColor() {
        var hex = ["#96ceb4", "#ffeead", "#ff6f69", "#ffcc5c", "#88db8b0", "#528491"];
        var color = hex[Math.floor(Math.random() * 6)]; // generates integer numbers [0,5], selects indexed item from hex
        return color;
        }

        function displayShape () {
            var percentages = [];
            for (var i=0; i<4; i++){ // generates a list with 4 different random integer values [5,60]
                percentages.push((Math.floor(Math.random() * 61) + 5));
            }
            var width = (Math.floor(Math.random() * 61) + 5); // generates integer numbers [5,60]
            var shapeRand = Math.random()
            if (shapeRand < 0.3) { // circle
                style.borderRadius = "50%";
            } else if (shapeRand >= 0.3 && shapeRand < 0.6) { // random shape
                style.borderTopLeftRadius = percentages[0] + "%";
                style.borderBottomRightRadius = percentages[1] + "%";
                style.borderTopRightRadius = percentages[2] + "%";
                style.borderBottomLeftRadius = percentages[3] + "%";
            } else { // square
                style.borderRadius = "0%";
            }
            //general shape styles
            style.width = width + "%";
            style.height = width + "%";
            style.display = "block";
            style.backgroundColor = getRandomColor();
            style.top = percentages[0] + "%";
            style.left = percentages[3] + "%";
            start = new Date().getTime(); // saves time when shape is created
            console.log(width);
            console.log(getRandomColor());
            console.log(shapeRand);
            console.log(percentages);

        }
        function displayShapeDelay () { // calls the main function with a delay between ]0s,2s[
            setTimeout(displayShape, Math.random() * 2000);
        }

        document.getElementById('stop').onclick = function() {

        }
    }

在我有这个之前:

我的目标是将 var 'time' 返回到全局范围,以便我可以使用它来创建每次单击时创建的每个值的数组。我已经意识到这不可能从匿名函数中实现。

document.getElementById('shape').onclick = function() { // calls the delay function
            style.display = "none";
            displayShapeDelay();
            end = new Date().getTime();
            time = (end - start)/1000 ;
            document.getElementById('timeBox').innerHTML = time + 's';
            return time
        }

所以这是我现在的代码:

var shapeClick = document.getElementById('shape');
        shapeClick.addEventListener("click", a, false);
        shapeClick.addEventListener("click", b, false);
        function a() {
            style.display = "none";
            displayShapeDelay(); // calls the delay function
        }
        function b() { 
            end = new Date().getTime();  // saves time when clicked
            var time = (end - start)/1000 ; // calculates interval from shape creation until click
            document.getElementById('timeBox').innerHTML = time + 's';
            return time;
        }
        document.getElementById('testbox').innerHTML = b();

现在,这有几个问题:

1-我似乎无法理解为什么在按下"开始"按钮后为两个"时间div"分配值。这意味着函数 b 正在运行,但它不应该只在 onClick 事件之后运行吗?

2-在"第一轮"中,我理解为什么两个值都显示为 NaN,因为还没有为变量"时间"赋值。但是在 onClick 事件执行后,在 'timeBox' 中分配的 'time' 值工作正常,但在函数外部调用的值则不能。函数 b 中的"返回时间"不是应该返回"时间"变量的值吗?

提前感谢!

粉彩之地

onclick函数充当大量代码的外部函数,这些代码在单击开始按钮时执行。此外,每次单击开始按钮时,它都会运行:单击多次快速启动以查看问题。 .

在 #start.onclick() 中,你有

document.getElementById('testbox').innerHTML = b();

在主线单击处理程序代码中:它不在另一个函数中,并在单击"开始"按钮时运行。由于尚未设置end,因此time的结果是 NaN .function b中的代码也设置 #timebox 的内容。

如果你在严格模式下运行代码,javascript 引擎会告诉你end尚未声明。它应该是 - 即使在全球范围内需要。

顺便说一句,仅供参考,Date.now()避免了创建和丢弃Date对象的需要,等效于new Date().getTime()

我建议重新设计代码以将 Pastel Land 的逻辑移动到开始按钮单击处理程序之外,并根据需要将单击处理程序调用到主应用程序代码中,但仅包含特定于启动操作本身的逻辑。如果要避免污染全局作用域,可以将所有代码包含在 IIFE(立即调用的函数表达式)中,该代码将提供与单击处理程序当前提供的相同作用域包含规定。善意地,我认为当前状态下的代码提出了一个 x-y 问题:-)


游戏

下面显示了 Pastel Land 的重组版本,原因如下:您有时间自己尝试,大部分代码都是您的,其余代码演示了建议的含义。这是一个非常愚蠢的游戏,值得玩!

<!DOCTYPE html>
<html>
<head>
<title>PastelLand</title>
<meta charset="utf-8">
<script>
window.addEventListener("load", function() // an IIFE
{"use strict"
   // Pastel Land
    var running = false;
    var start = 0;
    var end = 0;
    var times = []; // calculating average still to do
    var el, style;
    function getRandomColor() {
        var hex = ["#96ceb4", "#ffeead", "#ff6f69", "#ffcc5c", "#88db8b0", "#528491"];
        var color = hex[Math.floor(Math.random() * 6)]; // generates integer numbers [0,5], selects indexed item from hex
        return color;
    }
    function displayShape () {
        var percentages = [];
        for (var i=0; i<4; i++){ // generates a list with 4 different random integer values [5,60]
            percentages.push((Math.floor(Math.random() * 61) + 5));
        }
        var width = (Math.floor(Math.random() * 61) + 5); // generates integer numbers [5,60]
        var shapeRand = Math.random()
        if (shapeRand < 0.3) { // circle
            style.borderRadius = "50%";
        } else if (shapeRand >= 0.3 && shapeRand < 0.6) { // random shape
            style.borderTopLeftRadius = percentages[0] + "%";
            style.borderBottomRightRadius = percentages[1] + "%";
            style.borderTopRightRadius = percentages[2] + "%";
            style.borderBottomLeftRadius = percentages[3] + "%";
        } else { // square
            style.borderRadius = "0%";
        }
        //general shape styles
        style.width = width + "px";
        style.height = width + "px";
        style.position = "absolute"
        style.display = "block";
        style.backgroundColor = getRandomColor();
        style.top = percentages[0] + "%";
        style.left = percentages[3] + "%";
        start = Date.now(); // saves time when shape is created
        console.log(width);
        console.log(getRandomColor());
        console.log(shapeRand);
        console.log(percentages);
    }
    function displayShapeDelay () { // calls the main function with a delay between ]0s,2s[
        setTimeout(displayShape, Math.random() * 2000);
    }
    function readyAlert() {
            document.getElementById('readyContainer').style.display = 'none';
    }
    function userFound() {
        style.display = "none";
        end = Date.now(); 
        var time = (end - start)/1000 ; // calculates interval from shape creation until click
        document.getElementById('timeBox').innerHTML = time + 's';
        displayShapeDelay(); // calls the delay function
        times.push( time); // saves time user took to find shape
    }
    function userStart() {
        if( running)
            return;
        running = true;
        document.getElementById('readyContainer').style.display = 'block';  
        document.getElementById('readySeconds').innerHTML = '3'
        setTimeout(function() {document.getElementById('readySeconds').innerHTML = '2'}, 1000);
        setTimeout(function() {document.getElementById('readySeconds').innerHTML = '1'}, 2000);
        setTimeout(readyAlert,3000);
        setTimeout(displayShape, 3000);
        times.length = 0;  // reset times array
    }
    function userStop() {
        running = false;
        style.display="none"
    }
    function init() {
        el = document.getElementById('shape');
        style = el.style;
        el.addEventListener("click", userFound, false);
        document.getElementById('start').onclick=userStart;
        document.getElementById('stop').onclick=userStop;    
    }
    return init; // window load listener
}());
</script>
</head>
<body>
<div id='header'> <h1> Pastel Land </h1> </div>
<div id='container'>
    <div id='readyContainer'>
        <h3> This game will start in </h3>
        <h1 id='readySeconds'> </h1>
    </div>
    <div id='shape' style="height:40px;width:40px;"></div>
</div>
<div id='features'>
    <button id='start'> START </button> 
    <button id='stop'> STOP </button>
    <p id='timeBox'></p>
    <p id='timeAverageBox'></p>
</div>
<div id='testbox'> </div>
</body>
</html>

平均值的计算和显示以及对页面呈现的微小更改仍有待完成(我不是在编码它们!宽度和高度的单位从"%"更改为"px"(像素),并将"位置:绝对;"添加到shape.style中。函数ab组合成函数userFound。 涉及"testbox"的代码被省略了。IIEF 返回要在窗口加载后执行的初始化函数。


笔记

userStartuserStop单击事件处理程序是使用命名函数声明定义的,而不是将它们编码为调用其他函数的参数列表中的匿名函数。

声明

的函数名称是指由其声明创建的函数对象。因此,将元素的 onclick 属性的值设置为函数名称是有效的,因为该属性需要函数对象值。将onclick设置为调用其中一个处理程序返回的未定义值将不起作用。

启动/停止处理程序可以注册为"单击"事件侦听器,使用 addEventListener 而不是元素onclick值。

IIFE 不调用 init 函数。IIFE 本身在以下情况下被称为

window.addEventListener("load", function() { // IIFE code }() );

语句在页面的 head 部分中执行。此时将创建在 IIFE 中顶级声明的所有函数对象。IIFE 返回的函数 init 在为 HTML 正文创建所有 DOM 元素并触发窗口加载事件后,注册为稍后执行的侦听器。

如果您在其他elstyle初始化后从init调用userStart,游戏将开始。尽管通常调用 userStart 以响应单击开始按钮,但如果通过其他方式调用它,它的行为仍然相同。