javascript - 函数 Javascript || 的 NaN 返回值函数执行顺序

标签 javascript function variables scope

这里是 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,因为还没有为变量“time”分配值。但是在 onClick 事件执行后,'timeBox' 内部分配的 'time' 值可以正常工作,但在函数外部调用的则不能。函数 b 中的“返回时间”不是应该返回“时间”变量的值吗?

提前致谢!

最佳答案

粉彩之地

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

在#start.onclick() 中你有

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

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

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

顺便说一句,Date.now() 避免了创建和丢弃 Date 对象的需要,相当于 new Date().getTime() .

我建议修改代码,将 Pastel Land 的逻辑移到开始按钮点击处理程序之外,并让点击处理程序根据需要调用主应用程序代码,但只包含特定于开始操作本身的逻辑。如果你想避免污染全局范围,你可以将所有代码包含在 IIFE 中。 (立即调用的函数表达式)将服务于单击处理程序当前提供的相同范围包含规定。请注意,我认为当前状态下的代码呈现一个 x-y problem。 :-)


游戏

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”(像素)和“position:absolute;”添加到 shape.style。函数 ab 合并为函数 userFound。省略了涉及“testbox”的代码。 IIEF 返回一个在窗口加载后执行的初始化函数。


注意事项

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

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

启动/停止处理程序可能已经注册为“点击”事件监听器,使用addEventListener而不是元素 onclick 值。

init 函数由 IIFE 调用。 IIFE 本身在

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

语句在页面的头部执行。 IIFE 中在顶层声明的所有函数对象都在此时创建。 IIFE 返回的函数 init 被注册为监听器,以便在为 HTML 正文创建所有 DOM 元素并触发窗口加载事件后执行。

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

关于javascript - 函数 Javascript || 的 NaN 返回值函数执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36780257/

相关文章:

javascript - 尝试使用 JS 随机发生器或其他东西

javascript - 使用 javascript 删除 css 样式

javascript - 从 ajax 提供的 dataURI 创建视频文件

javascript - 如何根据作用域/闭包更新解构的 JavaScript 变量?

function - 将表名和列名定义为 plpgsql 函数中的参数?

c - 在函数中使用 malloc 和结构

javascript - 我可以将变量设置为对象的多部分属性吗?

variables - 在 Coldfusion8 application.cfc 中哪里定义应用程序和 session 变量?

c# - C# 中的静态变量

javascript - 模糊时隐藏 div