【问题标题】:Is it good a good practice to stringify array?字符串化数组是一个好习惯吗?
【发布时间】:2023-03-22 06:12:01
【问题描述】:

假设我有一个由布尔值组成的数组。

myArray = [false,false,false]

而且我需要根据每个状态做不同的事情。

前:

[false,true,false], [false,false,true], [true,true,false], ...

等等。

通常这种操作是通过检查每个单独的元素是否合适来完成的。

例如:

if(!myArray[0] && myArray[1] && !myArray[2]) do A
if(!myArray[0] && !myArray[1] && myArray[2]) do B
if(myArray[0] && myArray[1] && !myArray[2]) do C
...

而不是那样做。我将数组转换为字符串:

switch(JSON.stringify(myArray))
    case : "[false,true,false]"
        do A
        break
    case : "[false,false,true]"
        do B
        break
    case : "[true,true,false]"
        do C
        break
    ......

这被认为是好的做法吗?使用这种方法可能会遇到任何隐藏的错误吗? 这种方法会增加可读性吗?

【问题讨论】:

  • 感觉你的原始数组一开始就应该是一个位集,但这可能会因上下文而异。
  • ShioT 说了什么。你也可以尝试把它变成一个对象:{prop1: true, prop2: true,...}。这样您可以获得更多的可读性,因为您使用键来检查值。你现在这样做的方式,我可以想象它会很快变得混乱。如果您在几个月甚至几年后查看该代码,将很难弄清楚为什么这个订单会这样做,而另一个订单会做其他事情。
  • 没错,使用带命名的对象可能是比纯数组更好的解决方案。字符串化对象也应该产生一个更复杂的唯一字符串,具有更高的可读性
  • 您是否确信 JSON 字符串化操作已标准化到可靠且永远不会改变的程度?例如,某些特定的浏览器是否会将结果字符串化为"[false, false, false]"(带空格)?就 JSON 而言,它与结果一样有效,但会破坏您的代码……
  • @deceze 有可能,但很可能不会发生。 JSON.stringify() 有一个可选的“空格”参数,可以在需要时插入空格。默认情况下不应该添加空格。或者,如果您特别偏执并且想要安全。只需简单地添加 .replace(" ","") 以确保根本没有空格。

标签: javascript arrays switch-statement boolean


【解决方案1】:

关于使用 JSON.stringify

​​>

JSON.stringify 的使用将适用于(JSON 兼容的)基​​元的数组(数组(数组...)),即布尔值、字符串、数字、空值。没有歧义。 ECMAScript 规范也明确了不同值之间产生的“间隙”:它应该是空字符串,除非通过可选参数明确定义不同。见ECMAScript Language Specification on the topic

需要注意的是,undefined 不是 JSON 中的东西,因此 [null][undefined] 都将被字符串化为“[null]”。但由于您只使用falsetrue,这不是问题。

现在回答你的问题:

这算是好的做法吗?

这是一个见仁见智的问题。我的第一个直觉说“不”,主要是因为类型转换,但由于没有针对您的特定用例(即布尔数组)的警告,我们真的没什么可批评的。

使用这种方法我可能会遇到任何隐藏的错误吗?

没有

这种方法会增加可读性吗?

是的

然而,至少有一种替代方案具有所有相同的优点,但不依赖于某些数据类型转换:

替代方案:位集

如果您的数组是布尔数组,您可以选择使用数值数据类型,其中数字的每个二进制位对应于数组版本中的布尔值。

预计这种方法将比字符串化选项更有效,因为数据类型转换显然需要一些时间。

这是原始数组模式的运行:

let arr = [false, false, true];

if (!arr[0] && arr[1] && !arr[2]) console.log("do A");
if (!arr[0] && !arr[1] && arr[2]) console.log("do B");
if (arr[0] && arr[1] && !arr[2]) console.log("do C");

下面是使用 bitset 实现的相同逻辑:

let bitset = 0b001;

if (bitset === 0b010) console.log("do A");
if (bitset === 0b001) console.log("do B");
if (bitset === 0b110) console.log("do C");

如果您需要比数字数据类型(53 位)更多的位,那么您可以选择 BigInt。例如:

let bitset = 0b1010101010101010101010101010101010101010101010101010101n;

// A partial comparison
if ((bitset & 0b100010001n) === 0b100010001n) console.log("do A");

当然,没有必要使用0b字面量;这只是为了突出与数组版本的对应关系。您可以通过以十六进制表示法 (0x) 甚至纯十进制书写数字来保存一些字符,尽管后者对于您的代码的读者来说会更加晦涩。

【讨论】:

    【解决方案2】:

    它本身并没有太大问题,取决于上下文;有多少这些布尔值,它们来自哪里/它们是什么设置,有多少案例等。不好的部分可能是很难理解正在发生的事情和调试,特别是如果你有 10 多个值在那里。

    您也许可以将每个布尔值转换为在该上下文中表示某种含义的字符串/单词,这样您就得到了一个句子。如果每个布尔值都有一个唯一的词,则可以省略错误的词,因此您只需写下某些组合。

    你也可以使用myArray.join(',') 代替JSON.stringify(),它输出true,true,false(所以没有括号)。

    【讨论】:

      【解决方案3】:

      你的目标是写一个可读的 if?
      Stringify 是一个解决方案,但是(可能只对我来说)有点奇怪。

      这是我的建议。写一个这样的函数:

      isEqual(left, right) {
          if (left.length !== right.length) return false;
      
          for (var i = 0; i < left.length; i++) {
              if (left[i] !== right[i]) return false;
          }
      
          return true;
      }
      

      并像这样使用它:

      if (isEqual(array, [true, false, true]))  alert('isEqual');
      

      【讨论】:

      • 这似乎是一个不错的解决方案。但在循环的较大数据集中可能会面临一些性能下降。
      • 可以,但是比stringify和string-equals-check要小。
      猜你喜欢
      • 2017-08-09
      • 2016-01-03
      • 1970-01-01
      • 1970-01-01
      • 2015-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-22
      相关资源
      最近更新 更多