简体   繁体   English

如何理解用JavaScript编写的这种随机颜色函数?

[英]How to understand this randomising colour function written in JavaScript?

I'm a newbie when it comes to JavaScript and still have a lot to learn down the road. 我是JavaScript的新手,还有很多需要学习的东西。

Right now I'm trying to understand a method which is used to randomise the background colour of a webpage. 现在我正在尝试理解一种用于随机化网页背景颜色的方法。 The webpage has a button which will change the colour of the webpage by executing JavaScript function named "randColor" 该网页有一个按钮,通过执行名为“randColor”的 JavaScript函数来改变网页的颜色

The code can be seen below: 代码如下:

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); })('');
}

Now, I do understand several things from the randColor function: 现在,我从randColor函数中了解了几件事:

  • the "#" denotes the beginning of a hexadecimal colour value. “#”表示十六进制颜色值的开头。
  • I kinda understand the conditional ternary operator 我有点理解条件三元运算符

     (lor.length == 6) ? lor: co(lor); }) 

    It's basically a shortcut for the same expression that can be written like this: 它基本上是同一个表达式的快捷方式,可以像这样写:

     If(lor.length == 6)} lor = lor }else{ co(lor) // This calls co(lor) function recursively 
  • I understand the section right here as well: 我也理解这里的部分:

     [Math.floor(Math.random()*16)] 

    I'm sure this function is just a way to generate a random number between 0 and 16 and then round it down so it can correspond to a proper hexadecimal value. 我确信这个函数只是一种生成0到16之间随机数的方法,然后将其向下舍入,这样它就可以对应一个正确的十六进制值。

However, I don't understand how the whole thing works together. 但是,我不明白整个事情是如何协同工作的。 Would someone explain the rest to me? 有人会向我解释其余部分吗?

Good lord never write a function like this, it's ugly and there's literally no reason for it to be recursive. 好主人永远不会写这样的函数,它很丑陋,而且它实际上没有理由让它递归。 In any case this is just returning a function called co that that recursively calls itself until the length of the string it's passing around is 6. Here it is expanded: 在任何情况下,这只是返回一个名为co的函数,它递归调用自身,直到它传递的字符串的长度为6.这里它被展开:

function randColor() {
    function co(lor) {
        const digits = [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'];
        lor += digits[ Math.floor(Math.random()*16) ]; // (add digit at random index from 0-15)
        if (lor.length === 6) {
            return lor;
        } else {
            return co(lor);
        }
    }

    return '#' + co('');
}

and here's what execution would look like: 这是执行的样子:

Example Execution:
-> call randomColor()
-> call co("")
-> call co("f")
-> call co("fa")
-> call co("fa5")
-> call co("fa56")
-> call co("fa569")
// ^ Execution stops here
// fa569b is returned from the final co (notice a final digit is added first)
// '#' is added to the string
// and the full string is returned from randomColor.

lor += [0, 1, 2, ... adds a random hex digit. lor += [0, 1, 2, ...添加一个随机的十六进制数字。

The && makes sure the next expression is evaluated. &&确保评估下一个表达式。

(lor.length == 6) ? lor: co(lor); }) (lor.length == 6) ? lor: co(lor); }) adds another character to lor with co(lor) if it's not long enough, and if it is returns it. (lor.length == 6) ? lor: co(lor); })增加了另一个字符lorco(lor)如果它不是足够长的时间,如果是回报它。

Don't code like this; 不要这样编码; it's unreadable. 这是不可读的。

Breaking this down: 打破这个:

  • The return # + simply prepends a hashtag to the string, to represent the hash colour. return # +只是在字符串前面添加一个hashtag,以表示散列颜色。
  • The brackets wrapping around function co(lor) are an immediately-invoked function expression (IIFE) , which automatically executes, passing the empty string '' into the function (making lor a string). function co(lor)的括号是一个立即调用的函数表达式(IIFE) ,它自动执行,将空字符串''传递给函数(使lor成为字符串)。
  • The next part is a double return (joined with the && ), and according to Mozilla : 下一部分是双返回 (与&& ),并根据Mozilla

    expr1 && expr2 Returns expr1 if it can be converted to false; expr1 && expr2如果可以转换为false,则返回expr1; otherwise, returns expr2. 否则,返回expr2。 Thus, when used with Boolean values, && returns true if both operands are true; 因此,当与布尔值一起使用时,如果两个操作数都为真,则&&返回true; otherwise, returns false. 否则,返回false。

    1. [Math.floor(Math.random() * 16)] returns a random index of the array [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'] , essentially picking a hexadecimal character at random. [Math.floor(Math.random() * 16)]返回数组的随机索引[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'] ,基本上随机选取一个十六进制字符。 This gets appended to the existing string lor with lor += . 这将使用lor +=附加到现有字符串lor
    2. The ternary (lor.length == 6) ? lor : co(lor) 三元(lor.length == 6) ? lor : co(lor) (lor.length == 6) ? lor : co(lor) checks if the string lor contains 6 characters yet. (lor.length == 6) ? lor : co(lor)检查字符串lor包含6个字符。 If it does , it returns the string lor . 如果 ,则返回字符串lor If not , it returns co , passing lor (the current string) as the function parameter. 如果不是 ,则返回co ,将lor (当前字符串)作为函数参数传递。

Considering non-empty strings return true , the inner return basically just checks that the ternary is true . 考虑到非空字符串返回true ,内部return基本上只检查三元组是否为true And this ternary keeps re-calling the function until it contains exactly six hexadecimal characters, at which point they get returned as lor . 并且这个三元组不断重新调用函数, 直到它包含正好六个十六进制字符,此时它们将作为lor返回。

And this can all be seen in action: 这一切都可以在行动中看到:

 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); })(''); } 
 <button>Go!</button> 

Hope this helps clarify it a little! 希望这有助于澄清一点! :) :)

There're bunch of ways to acheive what you want, but basically, I am going to introduce some thing to keep in your mind when you do coding. 有很多方法可以实现你想要的东西,但基本上,我会在你编码的时候介绍一些让你记住的东西。

  1. Performance vs readability 性能与可读性

It's always on the table for debating. 它始终在争论的桌子上。 But, let's think there're 2 types of code that performs well within similar time. 但是,让我们认为有两种类型的代码在相似的时间内表现良好。 Then, you should consider readability more than performance, except you and your coworkers made certain rules for coding or it's a really sensitive project on speed, such as networking . 然后,您应该考虑可读性而不是性能, 除非您和您的同事制定了一些编码规则,或者它是一个非常敏感的速度项目,例如网络

  1. Call functions often? 经常打电话功能?

You should also consider this. 你也应该考虑这个。 For example, the function of yours, randColor (), basically generates rgb values several times. 例如,你的函数randColor ()基本上会多次生成rgb值。 But what if we can make an another function which generates numbers that are only related to colors? 但是,如果我们可以创建另一个生成仅与颜色相关的数字的函数呢? Something like this, 像这样的东西,

ranColor(){
    return '#' + ranRGB() + ranRGB() + ranRGB();
}

Well, though we don't know what's in ranRGB() , but at least we can say it's easier to read ranColor() , agree? 好吧,虽然我们不知道ranRGB()中有什么,但至少我们可以说它更容易阅读ranColor() ,同意吗? However, remember. 但是,请记住。 Like a coin has both sides, every behavior you choose will have a side effect no matter how big it is. 就像硬币有两面一样,你选择的每一个行为都会产生副作用,无论它有多大。 What I mean is, if calling ranRGB() function inside ranColor() wasn't really meaningful and necessary either, it could mean you wasted your memory. 我的意思是,如果在ranColor()中调用ranRGB()函数也不是真正有意义和必要,它可能意味着你浪费了你的记忆。 So, always be careful when you separate code blocks. 因此,分开代码块时要小心。

  1. Always think. 一直在想。 "Is this the best way?" “这是最好的方式吗?”

Honestly, the majority of people who are studying programming will end up having similar skills at the end, except few genius. 老实说,大多数正在学习编程的人最终都会有类似的技能,除了少数天才。 Meaning is, whether you're evaluated as a good programmer or not could simply be decided by your coding style, habbit, traces that makes people reading your codes think 'how deeply' this programmer had thought about his/her codes. 意思是,无论你是否被评价为优秀的程序员,都可以简单地通过你的编码风格,习惯,使人们阅读你的代码的痕迹来决定这个程序员对他/她的代码的思考“有多深”。


Anyway, if I were you, I probably would do like this. 无论如何,如果我是你,我可能会这样做。

function ranColor(){
    return 'rgb(' + ranNum() ',' + ranNum() + ',' + ranNum() + ')';
}

function ranNum(){
    return Math.round(Math.random() * 256);
}
var rgb = ranColor();

Let me break it down in detail for you: 让我详细介绍一下:

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); })('');
}

The most important info about this code is that: whoever wrote this code probably lives in hell. 关于这段代码最重要的信息是: 编写此代码的人可能生活在地狱中。

Let me re-write the function in a exact but clearer way and add some comments in it, and perhaps you'll understand better: 让我以一种更准确但更清晰的方式重新编写函数并在其中添加一些注释,也许你会更好地理解:

function randColor(){
    // Create a function that generates hex value
    var co = function(lor){
        // Array of all possible number/alphabet for hex value
        var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];

        // Add a random item from `list` to `lor`
        // `Math.floor(Math.random()*16)` generates a random number from 0 to 16
        // If the random number generated is `10`, that means
        // list[10], which is value 'a'.
        // So, lor += 'a'
        lor += list[Math.floor(Math.random()*16)];

        return lor.length == 6    // If lor.length === 6
               ? lor              // Returns the hex color value, else
               : co(lor);         // Recursively call the `co` function
                                  // to add more item to `lor`, until it reaches a length of 6.
    };

    // Calls `co` function with an empty string as argument (serves as `lor`)
    // Then concatenate '#' to co's value
    // A random hex color value is formed.
    return '#' + co('');
}

Now, the function could have been better simplified: 现在,该功能可以更好地简化:

 document.querySelector("button").addEventListener("click", function(){ this.innerText = randColor(); }) function randColor(hex){ var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']; /** * If hex is not defined * hex = '#' * else * hex = hex */ hex = hex || '#'; hex += list[Math.floor(Math.random()*16)]; return hex.length === 7 ? hex : randColor(hex); } 
 <button>Start</button> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM