【问题标题】:Can someone fluent in Javascript explain to me whats going on here SIMPLY能流利使用 Javascript 的人可以简单地向我解释一下这里发生了什么吗
【发布时间】:2018-03-12 22:52:36
【问题描述】:

我正在参加有关 udemy 的课程,并且遇到了更改窗口背景的这段代码。问题是功能 randColor 失去了我。我想确切地知道发生了什么。

我知道声明了一个名为 randColor 的函数,然后该函数本身返回一个函数 + # 但我试图了解这一切发生的逻辑。添加了一个 HASH 符号,我相信它也是一个 IIFE 对吗?

非常感谢您的帮助!

document.querySelector("button").addEventListener("click", function(){
  document.body.style.background = randColor();
})


function randColor(){
  return '#' + (function co(lor){   return (lor +=
    [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)])
    && (lor.length == 6) ?  lor : co(lor); })('');
}

【问题讨论】:

  • 哇,多么可怕的代码。它是一个递归的 IIFE,而不是一个简单的循环,具有模糊的单行正文而不是两个语句,具有奇怪的基本情况条件。
  • @Bergi 代码有什么“可怕”之处?
  • @guest271314 你需要解释它的事实。它以一种难以理解的方式做了一件微不足道的事情。
  • @guest271314 - 您是否同意通过直接编码也可以达到同样的效果而不会降低效率?
  • @blex 不,这不起作用。你需要.padStart(6, "0")(而且你不应该乘以一个字符串)

标签: javascript function iife


【解决方案1】:

目标是生成 Hex 格式的随机颜色。我试图解释您提供给我们的代码:

randColor 被调用时,它会被添加到调用堆栈中,然后暂停等待嵌套函数的调用完成。

嵌套函数co(lor) 是IIFE,它被递归调用。 最初传入一个空字符串,并为其分配本地lor 变量。

Math.floor(Math.random()*16) - 生成从 0 到 15 的数字,它们是 数组[0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'] 的索引。在每一步,数组中的一个新符号都会添加到之前作为参数传入的本地 lor 字符串中。如果更新后的字符串长度小于 6,则将其进一步传递到新调用中。

嵌套函数的递归添加到具有lor 值的调用堆栈对象,如下所示(例如):

5aTh46 (top, last call, gets popped out first)
5aTh4
5aTh
5aT
5a
5      (first call)

当本地lor变量的长度在第6次调用后等于6时,则满足基本条件lor.length == 6并从调用堆栈顶部返回5aTh46字符串。所以,对于第 5 个电话,我们有

return (lor += [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'] [Math.floor(Math.random()*16)]) && (lor.length == 6) ? lor /* = 5aTh4*/ : co(lor) /* = 5aTh46*/;

lor.length == 6 为假,因为本地 lor 等于 5aTh4。因此,第 6 次调用返回的 5aTh46 在第 5 次调用之后也会返回,依此类推,直到值 5aTh46 作为 co(lor) 调用的结果最终返回并添加到 @987654342 内的 # 字符串中@。最后我们得到#5aTh46

PS。我就是这么理解的。如果您了解event loopIIFE 的概念,这个解释可能听起来很简单:)

【讨论】:

  • 感谢您的帮助,我非常感谢 - 我只是迷路了,因为返回后的部分让我失望 - 为什么返回后会有一个 OPENING 括号?我从来不知道那是有效的javascript。另外为什么数组不用逗号分隔?返回(lor += [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'] [Math.floor(Math.random()*16)]) && (lor.length == 6) ?洛尔:co(洛尔); ^ 这就是说 lor = lor+ 字母/数字乘以 1 到 16 之间的整数,如果 lor 的长度 == 6,那么呢?
  • 简而言之,1)返回后有一个 OPENING 括号 - 它是 IIFE 的一部分,在这种情况下看起来像 (function(){})()。如果整个事物是表达式的一部分,也可以像这样function(){}()。 2)为什么数组没有用逗号分隔? - 只有 1 个符号数组。另一对[] 包含计算索引。就像['a', 'b'][1] (= 'b') 但索引1 是即时计算的。
  • 3) 返回 (lor += [0,1,2,3,4,5,6,7,8,9,'a','b','c','d ','e','f'][Math.floor(Mat‌​h.random()*16)]) && (lor.length == 6) ?洛尔:co(洛尔); - 这是使用条件运算符[cond to evaluate] ? [if true] : [if false]。整件事说:向lor 添加一个符号,如果lor 的长度为6,则返回lor。否则继续调用co(lor)(直到它的长度达到6个符号)。
  • 所以,要掌握的东西:IIFE、数组、条件运算符和递归。
  • 好吧,我想我明白了,所以我在 codepen 中做了一些测试——基本上这整个部分是一个三元运算符,它是 if/else 语句的更好版本---- return (lor += [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor( Math.random()*16) ]) && (lor.length == 6) ? lor :co(lor);--- 它的说法 - IF lor = lor + 随机字符串 AND 长度 === 6, THEN lor ELSE co(lor) 对吗?
【解决方案2】:

是的。这是一个IIFE。调用以'' 开头。然后进行递归调用,每次从数组[0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'] 随机附加一个字符。添加了六个这样的字符(由(lor.length == 6) 检查)。前面的 '#' 被添加到第 6 个字符之前,以形成由函数 randColor() 返回的随机颜色。

【讨论】:

    【解决方案3】:
    (function co(lor /* passed empty string */){ /* concatenate result of `co("")` */  return (lor +=
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)])
           // if `lor` string `.length` is `6` return `lor` string 
           // else call `co` with `lor` as parameter
        && (lor.length == 6) ?  lor : co(lor); })('' /* empty string */)
    

    【讨论】:

    • "lor 作为参数调用co" - 是的,这显然是co(lor) 的语法含义。但它有什么作用,为什么?
    • @Bergi "concatenate result of `co("")`"
    • 不,co(lor) 不会“连接co("")的结果
    • @Bergi co(lor) 根据lor.length 返回co(lor)lor,初始调用是co(""),其中lor""跨度>
    • @Bergi co(lor)的最终结果连接到"#"
    【解决方案4】:

    代码起初看起来很糟糕。让我们一步一步简化。

    //find 1st <button> element and assign on'click' handler to it
    document.querySelector("button").addEventListener("click", function(){
      document.body.style.background = randColor();
      //background is the **result** of execution of randColor()
    })
    
    
    function randColor(){
      return '#' + (function co(lor){   return (lor +=
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)])
        && (lor.length == 6) ?  lor : co(lor); })('');
    }
    

    randColor() 返回一个包含函数的表达式(实际上是IIFE)。
    让我们把结果而不是函数调用。同时,由于前面有+操作符,所以这里的函数括号可以省略。

    document.querySelector("button").addEventListener("click", function(){
      document.body.style.background = '#' + function co(lor){
       return (lor +=
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)])
        && (lor.length == 6) ?  lor : co(lor); }(''/*send empty string to lor parameter*/);
    })
    

    还不容易?让我们进行下一步。

    document.querySelector("button").addEventListener("click", function(){
      document.body.style.background = '#' + co(''/*send empty string to lor parameter*/);
    })
    
    function co(lor){
       return (lor += /*assignment returns the new value. always truey in this case*/
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)/*magic 16 is the array length*/])
        && (lor.length == 6) ?  /*returns when we have 6 character string*/lor : /*call the function recursively*/co(lor); 
    }
    

    最后的简化。使用循环而不是递归。

    function co(){
       var lor = '';
       var hexDigits = '0123456789abcdef'.split('');
       for(var i = 0; i < 6/*required length*/;i++){
         lor += hexDigits[Math.floor(Math.random() * 16)/*0 - 15*/];
       }
       return lor;
    }
    

    前导 # 构成颜色的正确 HEX 值。

    【讨论】:

      【解决方案5】:

      我想提出一个更简化的迭代代码而不是递归。

         <script type="text/javascript">
          document.querySelector("button").addEventListener("click", function(){
              // body
              document.body.style.background=randcolor();
          })
      
          function randcolor(){
      
              var list=['1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'];
              var r='#';
              while(r.length<7)
              {
                  r+=list[Math.floor(Math.random()*16)];
              }
              return r;
          }
      
      </script>
      

      【讨论】:

        【解决方案6】:

        “#”是颜色代码的一部分(#7b7b6e),该函数返回一个类似“7b7b6e”的随机字符串,并在其前面添加#

        【讨论】:

        • 我们知道它在做什么。 OP 正在询问如何此代码实现这一目标。
        猜你喜欢
        • 1970-01-01
        • 2012-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-19
        • 2020-05-31
        相关资源
        最近更新 更多