【问题标题】:JavaScript shorten repeating code for generating random CSS colorJavaScript 缩短用于生成随机 CSS 颜色的重复代码
【发布时间】:2016-04-27 15:26:46
【问题描述】:

我决定无缘无故地制作一个随机的十六进制颜色生成器。它工作正常,但它需要写

var value1 = hexArray[Math.floor(Math.random() * hexArray.length)];" 6次。我怎样才能解决它,所以我不这样做?如果我做这样的事情

var rand1 = rand2 = rand3 ect. = hexArray[Math.floor(Math.random() * hexArray.length)]; 它将打印出所有具有相同数字/字母的值。有什么建议吗?

    var hexArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
    var rand1 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var rand2 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var rand3 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var rand4 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var rand5 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var rand6 = hexArray[Math.floor(Math.random() * hexArray.length)];
    var array2 = [rand1, rand2, rand3, rand4, rand5, rand6]
    var value = "#" + array2.join("");

    //ignore this
    $(document).ready(function() {
      $("body").css("background-color", value);
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

【问题讨论】:

  • 如果你的混淆值和 rand 的意思是一样的
  • var value1 = hexArray[Math.floor(Math.random() * hexArray.length)];
  • var randomColor = "#"+("00000"+Math.floor(Math.random()*0x100000).toString(16)).substr(-6); - 更简单,不是吗? ;)
  • 谢谢你的遮阳篷

标签: javascript jquery dry


【解决方案1】:

cmets 已经提供了简短的答案,但我将在这里详细说明我们如何得到它。


第 1 部分:

var rand1 = hexArray[Math.floor(Math.random() * hexArray.length)];
var rand2 = hexArray[Math.floor(Math.random() * hexArray.length)];
var rand3 = hexArray[Math.floor(Math.random() * hexArray.length)];
var rand4 = hexArray[Math.floor(Math.random() * hexArray.length)];
var rand5 = hexArray[Math.floor(Math.random() * hexArray.length)];
var rand6 = hexArray[Math.floor(Math.random() * hexArray.length)];

这部分可以更改为使用数组和循环。可以做到这一点的一个巨大好处是,您的变量名中有序列号。但是,因为数组通常是从零开始的,所以我不会使用 1-6 而是 0-5 作为索引。在我的循环中,我正在计算一个从 0 到 5 的变量(尽管我正在检查它是否是 < 6 而不是 <= 5 以提高可读性 - 很明显它运行了 6 次)并填充数组。像这样:

var rand = [];
for(var i = 0; i < 6; i++) {
    rand[i] = hexArray[Math.floor(Math.random() * hexArray.length)];
}

那么我们可以改变这个...

var array2 = [rand1, rand2, rand3, rand4, rand5, rand6];

...到这个:

var array2 = [rand[0], rand[1], rand[2], rand[3], rand[4], rand[5]];

...没有多大意义,可以用另一个循环代替:

for(var i = 0; i < rand.length; i++) array2[i] = rand[i];

现在这基本上只是将整个数组rand 复制到array2 中,因此我们可以将其简化为:

var array2 = rand;

好的,但现在总的来说是这样的:

var rand = [];
for(var i = 0; i < 6; i++) {
    rand[i] = hexArray[Math.floor(Math.random() * hexArray.length)];
}
var array2 = rand;

应该清楚的是,我们可以从一开始就使用array2,或者——更有意义的是,因为变量名更有意义——我们可以继续使用rand,而不是创建一个新数组array2,所以我们会改变这个......

var value = "#" + array2.join("");

...到这个:

var value = "#" + rand.join("");

作为最后的改进,我们可以不总是在上面的循环中指定我们想要创建的数组元素 (rand[i] = ...),而是继续推入数组 (rand.push(...)),它会自动创建一个新元素每次增加ID:

var rand = [];
for(var i = 0; i < 6; i++) {
    rand.push(hexArray[Math.floor(Math.random() * hexArray.length)]);
}

所以,此时代码如下所示:

var hexArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
var rand = [];
for(var i = 0; i < 6; i++) {
    rand.push(hexArray[Math.floor(Math.random() * hexArray.length)]);
}
var value = "#" + rand.join("");

//ignore this
$(document).ready(function() {
  $("body").css("background-color", value);
});
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

这应该已经回答了您最初的问题,因为它消除了重复。但是等等,我们还可以做更多的事情!


第 2 部分:

您对hexArray 所做的实际上是在尝试生成一个随机的十六进制数字。既然我把它放到这句话中,应该很清楚实际上我们可以用更简单的方式来做到这一点:生成一个随机值并将其转换为它的十六进制表示!

可以使用Math.random() 生成一个随机值,它将输出一个大于或等于零且小于一的随机值(例如0.292835430.917240.18283123255,你懂的)。

为了得到一个介于零和另一个值之间的随机数,我们可以将Math.random() 的结果乘以唯一的最大值,在我们的例子中是 16。

Math.random() * 16 将给出像3.18237214.22229355.190023 这样的数字,这几乎是我们想要的,但我们只想得到整数(没有小数部分)。我们通过将结果输入Math.floor 来得到这个,它会向下取整,所以Math.floor(Math.random() * 16) 会给出3145 之类的东西,这正是我们所需要的。

这基本上是你已经做的,因为hexArray.length16我只是解释了它,因为人们可能开始使用someArray[Math.floor(Math.random() * someArray.length)] 成语而不真正了解它是如何工作的。

但是,当我们将输入的数字填充到字符串中时,它们将是十进制的。我们希望它们采用十六进制表示,以便前面示例中的14 将变为e。这可以通过对数字调用 toString 方法来完成,该方法接受一个指定数字基数的可选参数(例如,var number = 123; console.log(number.toString(16)); 将输出 7b)。

因此,我们可以使用以下方法获得一个随机的十六进制数字:

Math.floor(Math.random() * 16).toString(16)

所以让我们再次简化我们之前的代码,并更改它...

var hexArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
var rand = [];
for(var i = 0; i < 6; i++) {
    rand.push(hexArray[Math.floor(Math.random() * hexArray.length)]);
}

...到这个:

var rand = [];
for(var i = 0; i < 6; i++) {
    rand.push(Math.floor(Math.random() * 16).toString(16));
}

所以整个代码现在看起来像这样:

var rand = [];
for(var i = 0; i < 6; i++) {
    rand.push(Math.floor(Math.random() * 16).toString(16));
}
var value = "#" + rand.join("");

//ignore this
$(document).ready(function() {
  $("body").css("background-color", value);
});
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

但是,嘿,我们还没有完成!


第 3 部分:

让我们回顾一下这段代码的作用:

  1. 它创建一个数组。
  2. 它将 6 个随机十六进制数字推入数组。
  3. 它加入数组并在前面添加 #,以创建 CSS 颜色值。
  4. 它在 CSS 中设置背景颜色。

现在第 1-3 点可以进一步简化,因为最后,我们基本上是在创建一个随机的 6 位十六进制值

在第 2 步中,我们开始使用 Math.random(Math.floor() * 16).toString(16) 创建一个介于 0 和 16 之间(唯一)的随机值,并将其转换为十六进制表示。为了清楚起见,让我将这里的第一个 16 也更改为十六进制(如果您不知道,可以通过在它们前面加上 0x 来使用十六进制文字):

Math.random(Math.floor() * 0x10).toString(16)

我们可以使用相同的机制来创建一个介于 0 和 0xFFFFFF(包括)之间的随机值,即 0 和 0x1000000(不包括),如下所示:

Math.random(Math.floor() * 0x1000000).toString(16)

这将为我们提供随机值,例如 0x29F3D5(十进制 2749397)、0xC720FE(十进制 13050110)等。

这听起来正是我们需要的,对吧?嗯,差不多。随机值可能小于 0x100000 在这种情况下它们将少于 6 位,例如0xE81C 或 0x12345!

这意味着我们必须在左边用零填充它以始终准确地有 6 位数字,不少于。不幸的是,没有优雅的内置方法可以做到这一点,所以如果需要,我们必须手动添加零。所以当随机函数给我们字符串E81C时,我们将不得不添加两个零以使其成为00E81C

当然,我们可以计算现有字符串的长度并计算6 - length,然后添加那么多零……但是有一种更简单的方法可以做到这一点。由于我们知道我们将始终有至少一个数字和最大 6,并且我们总是想要 6,这意味着我们必须根据现有长度添加 0 到 5 个零。我们现在可以假设最坏的情况,总是加 5 个零

"00000" + Math.floor(Math.random() * 0x1000000).toString(16)

当然,这意味着字符串现在通常太长(6 到 11 个字符之间),但我们可以通过仅使用最后 6 个字符来解决这个问题,这可以使用字符串方法 substr 来完成。由于确切解释调用substr 的不同方式会使这个已经很长的答案长,我将链接到the documentation for this method 以供进一步阅读并告诉你可以使用负值作为参数从右边提取一定数量的字符。例如,"hello".substr(-3)" 会给你llo

所以,知道了这一点,我们可以构建代码,它总是再次给我们 6 个随机十六进制数字:

("00000" + Math.floor(Math.random() * 0x1000000).toString(16)).substr(-6)

请注意,我必须在 .substr 之前添加括号,否则 substr 方法将仅在 + 的右侧调用,而不是整个调用。

让我们将这种新方法付诸实践。我们可以替换整个rand 数组和rand.join("") 部分。代码现在看起来像这样:

var value = "#" + ("00000" + Math.floor(Math.random() * 0x1000000).toString(16)).substr(-6);

//ignore this
$(document).ready(function() {
  $("body").css("background-color", value);
});
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

这就是我们登陆the code suggested by Niet the Dark Absol in the comments的方式!

2020 年更新:如今,substr 技巧已不再需要,因为 padStart 已成为标准。所以,我们可以改用"#" + Math.floor(Math.random() * 0x1000000).toString(16).padStart(6, '0')


我知道这是一个非常冗长的答案,也许您已经知道其中的大部分内容,但也许不知道。也许您或其他读者会摸不着头脑,我们是如何得出这个结果的,或者可能有哪些其他优化步骤。这就是我写这篇攻略的原因。 :)

【讨论】:

    【解决方案2】:

    您不需要单独生成每个十六进制字符。只需生成一个随机数 0 和 2^24 并将其转换为十六进制:

    var pad = "00000"
    var random = Math.floor(Math.random() * (0x1000000))
    var randomHex = random.toString(16)
    var color = "#" + pad.substring(0, 6 - randomHex.length) + randomHex
    

    更新:浏览答案here,有一些不错的技巧,但除了接受的答案之外,颜色要么不是正确随机的、正确填充的,要么是太长的。这是另一个在这两个方面都应该正确的版本:

    var random = Math.floor(Math.random() * (1<<24))
    var color = "#" + ("00000" + random.toString(16)).substr(-6)
    

    【讨论】:

    • 0xFFFFFF 应该是 0x1000000
    【解决方案3】:
    var hexArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
    var array2 = [];
    for (i = 0; i <= 5; i++) {
      array2.push(hexArray[Math.floor(Math.random() * hexArray.length)]);
    }
    var value = "#" + array2.join("");
    
    $('div').css("background-color", value);
    

    【讨论】:

      【解决方案4】:

      这对我来说是最简单的。一行,简单。

      var randomColor = "#" + Math.floor(Math.random() * parseInt(0x1000000)).toString(16);
      

      【讨论】:

      • 如果您的随机数小于 0x100000,这将产生无效的颜色,例如 #12345。我上面的回答在最后处理了这个问题。但是请注意,现在有一种更简单的方法:padStart,因此您只需在末尾添加.padStart(6, '0')
      猜你喜欢
      • 2013-02-26
      • 2013-12-31
      • 2017-08-03
      • 2020-11-27
      • 2011-07-02
      • 1970-01-01
      • 2013-11-22
      • 1970-01-01
      相关资源
      最近更新 更多