【问题标题】:Does JavaScript have a method like "range()" to generate a range within the supplied bounds?JavaScript 是否有类似“range()”的方法来在提供的范围内生成范围?
【发布时间】:2017-09-09 02:52:11
【问题描述】:

在 PHP 中,你可以这样做...

range(1, 3); // Array(1, 2, 3)
range("A", "C"); // Array("A", "B", "C")

也就是说,有一个函数可以让你通过传递上限和下限来获取一系列数字或字符。

JavaScript 是否有内置的东西?如果没有,我将如何实现它?

【问题讨论】:

  • Prototype.js 有$R 功能,但除此之外我不这么认为。
  • 这个(相关)问题有一些很好的答案:stackoverflow.com/questions/6299500/…
  • Array.from("ABC") //['A', 'B', 'C'] 这是我能找到的最接近问题第二部分的内容。
  • 当情人绑定为零时这个oneliner:Array.apply(null, { length: 10 }).map(eval.call, Number)
  • 否,但您可以使用以下方式定义函数:const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));(参见 MSDN 中的 'Sequence generator (range)'注意:此函数仅在指定所有参数时才有效(即。 range(1,5,1) 生成数组 [1,2,3,4,5],但 range(1,5) 生成一个空数组)

标签: javascript arrays functional-programming


【解决方案1】:

我的实现

export function stringRange(a: string, b: string) {
    let arr = [a + ''];

    const startPrefix = a.match(/([\D])+/g);
    const endPrefix = b.match(/([\D])+/g);

    if ((startPrefix || endPrefix) && (Array.isArray(startPrefix) && startPrefix[0]) !== (Array.isArray(endPrefix) && endPrefix[0])) {
        throw new Error('Series number does not match');
    }

    const startNum = a.match(/([\d])+/g);
    const endNum = b.match(/([\d])+/g);

    if (!startNum || !endNum) {
        throw new Error('Range is not valid');
    }

    let start = parseInt(startNum[0], 10);
    let end = parseInt(endNum[0], 10);

    if (start > end) {
        throw new Error('Ending value should be lessesr that starting value');
    }

    while (start !== end) {
        start++;
        arr.push(startPrefix ? startPrefix[0] + (start + '').padStart(startNum[0].length, '0') : start + '');

    }

    return arr;
}

样本结果

// console.log(range('0', '10'));
// console.log(range('10', '10')); 
// console.log(range('10', '20'));
// console.log(range('10', '20000'));
// console.log(range('ABC10', 'ABC23'));
// console.log(range('ABC10', 'ABC2300'));
// console.log(range('ABC10', 'ABC09')); --> Failure case
// console.log(range('10', 'ABC23')); --> Failure case
// console.log(range('ABC10', '23')); --> Failure case

【讨论】:

    【解决方案2】:

    d3 也有一个内置的范围函数。

    https://github.com/d3/d3-array#range:

    d3.range([start, ]stop[, step])

    生成一个包含算术级数的数组,类似于 Python 内置的范围。此方法通常用于迭代一系列数字或整数值,例如数组的索引。与 Python 版本不同,参数不需要是整数,但如果是浮点精度,结果更容易预测。如果省略 step,则默认为 1。

    例子:

    d3.range(10)
    // returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    【讨论】:

    • 我从来不知道 D3 的存在。不会使用他们的 range 方法,但会使用这个包。
    • 非常感谢。我使用 D3 并正在寻找一个原生 JS 方法,不知道我 D3 已经提供了它。
    【解决方案3】:

    已经给出了很好的答案,但是我没有看到完全使用 ES6 迭代器来实现range 的完整实现,所以这里是:

    /**
     * inspired by Python's built-in range utility function
     * implemented using ES6 Iterable, Iterator  protolols (interfaces)
     */
    class Range {
      constructor(...args) {
        this.start = args.length <= 1 ? 0 : args[0];
        this.end = args.length <= 1 ? args[0] || 0 : args[1];
        this.step = args.length <= 2 ? 1 : args[2];
      }
    
      [Symbol.iterator]() {
        return this;
      }
    
      next() {
        if (this.end > this.start) {
          const result = { done: false, value: this.start };
          this.start = this.start + this.step;
          return result;
        } else return { done: true, value: undefined };
      }
    }
    
    /**
     * Symbol.iterator is part of the couple of inbuilt symbols
     * available in JavaScript. It allows for hooking into the
     * inbuilt for of iteration mechanism. This is why the
     * Symbol.iterator comes into play when talking about
     * iterables and iterators in JavaScript.
     */
    
    function range(...args) {
      return new Range(...args);
    }
    
    console.log([...range(4)]);        // [0, 1, 2, 3]
    console.log([...range(2, 5)]);     // [2, 3, 4]
    console.log([...range(1, 10, 3)]); // [1, 4, 7]
    

    【讨论】:

      【解决方案4】:

      这是实现您自己的可迭代范围函数的方法。

      // implementing range
      function range(start, end){
          return {
            from: start,
            to: end,
      
            [Symbol.iterator]() { 
              this.current = this.from;
              return this;
            },
      
            next() { 
              if (this.current <= this.to) {
                return { done: false, value: this.current++ };
              } else {
                return { done: true };
              }
            }
          };
      
      }
      
      // iterate over each value
      for (let num of range(1,5)) {
        console.log(num); // 1, 2, 3, 4, 5
      }

      【讨论】:

      • 使迭代器对象可重用的有趣方式:)
      • @Bergi 谢谢 :)
      【解决方案5】:

      Op 要求一个范围,比如 range(3, 10),所以它可以是

      [...[...Array(10-3).keys()].map(i => i+3)]
      

      返回

      [3, 4, 5, 6, 7, 8, 9]
      

      【讨论】:

        【解决方案6】:
        (from, to) => [...Array(to - from)].map((_,i)=> i + from)
        

        【讨论】:

          【解决方案7】:

          function range(firstNum, lastNum) {
            let rangeList = [];
            if (firstNum > lastNum) {
              return console.error("First number cannot be bigger than last number");
            }
          
            let counter = firstNum;
            while(counter <= lastNum) {
              rangeList.push(counter);
              counter++;
            }
          
            return rangeList;
          }

          【讨论】:

          • 这里还有很多其他的答案。这与其他的有何不同?
          【解决方案8】:

          您还可以使用生成器来生成序列。 不同之处在于序列中的每个值都是延迟加载的。传播运算符和结果的工作。 星号符号使函数成为生成器。

          const range = function*(from,to) {   
              for(let i = from; i <= to; i++) yield I;   
          };   
          
          [...range(3,5)]// => [3, 4, 5]
          

          【讨论】:

            【解决方案9】:

            如果在 Visual Studio 代码中遇到错误:

            Type 'IterableIterator' 不是数组类型或字符串类型。使用编译器选项“--downlevelIteration”来允许迭代器的迭代。

            代替

            [...Array(3).keys()]
            

            你可以信赖

            Array.from(Array(3).keys())
            

            更多关于downlevelIteration

            【讨论】:

              【解决方案10】:

              在 Vue 中循环 0 到 Length 之间的数字范围:

              
              <div v-for="index in range" />
              
              computed: {
                 range () {
                      let x = [];
              
                      for (let i = 0; i < this.myLength; i++)
                      {
                          x.push(i);
                      }
              
                      return x;
                  }
              }
                  
              

              【讨论】:

              • 对于这么老的帖子,您需要添加一些评论,说明您的答案为何优于该主题的其他 69 个答案。对于这样的帖子,纯代码根本不可接受,任何用户应该如何从所有这些帖子中挑选出你的?
              • 现在是 2021 年,这个线程充满了实现这一基本操作的完全过于复杂的方法。像我这样的一些用户希望看到一些易于理解的东西。更新了我的代码,为 vue 用户提供上下文
              • OP 甚至没有提及使用 Vue。
              • 欢迎来到 2021
              【解决方案11】:

              ES6

              使用 Array.from(文档here):

              const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
              

              【讨论】:

                【解决方案12】:

                对于行为类似于 python range() 函数的函数,使用这个:

                function range(min=0, max=null){
                    if(max === null){
                        max=min;
                        min=0;
                    }
                    var rg=[...Array(max).keys()];
                    return rg.slice(min,max);
                }   
                
                

                【讨论】:

                  【解决方案13】:

                  您可以创建自己的 es6 range 版本

                  const range = (min, max) => {
                    const arr = Array(max - min + 1)
                      .fill(0)
                      .map((_, i) => i + min);
                    return arr;
                  }
                  
                  console.log(range(0,5));
                  
                  console.log(range(2,8))

                  【讨论】:

                    【解决方案14】:

                    这是我的 2 美分:

                    function range(start, end) {
                      return Array.apply(0, Array(end - 1))
                        .map((element, index) => index + start);
                    }
                    

                    【讨论】:

                    • 这实际上是错误的,因为问题是要求开始和结束值。不开始和计数/距离。
                    • 这个答案没有按预期工作。输出不可用。
                    【解决方案15】:

                    我个人最喜欢的:

                    const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
                    

                    【讨论】:

                    • 或许更好[...Array(end-start+1)].map((el, ind) =&gt; ind + start);?
                    【解决方案16】:

                    使用这个。它创建一个具有给定数量的值(未定义)的数组,在以下示例中有 100 个索引,但它不相关,因为这里您只需要键。它在数组 100 + 1 中使用,因为数组始终基于 0 索引。因此,如果要生成 100 个值,则索引从 0 开始;因此最后一个值总是 99 而不是 100。

                    range(2, 100);
                    
                    function range(start, end) {
                        console.log([...Array(end + 1).keys()].filter(value => end >= value && start <= value ));
                    }

                    【讨论】:

                      【解决方案17】:

                      简单的范围函数:

                      function range(start, stop, step) {
                          var a = [start], b = start;
                          while (b < stop) {
                              a.push(b += step || 1);
                          }
                          return a;
                      }
                      

                      要合并BigInt data type,可以包括一些检查,确保所有变量都相同typeof start

                      function range(start, stop, step) {
                          var a = [start], b = start;
                          if (typeof start == 'bigint') {
                              stop = BigInt(stop)
                              step = step? BigInt(step): 1n;
                          } else
                              step = step || 1;
                          while (b < stop) {
                              a.push(b += step);
                          }
                          return a;
                      }
                      

                      删除高于stop 定义的值,例如range(0,5,2) 将包括 6,这不应该。

                      function range(start, stop, step) {
                          var a = [start], b = start;
                          while (b < stop) {
                              a.push(b += step || 1);
                          }
                          return (b > stop) ? a.slice(0,-1) : a;
                      }
                      

                      【讨论】:

                      • 加上 UNO 的可用性和可读性。很久以来见过的最好的代码sn-p。
                      • 这在step != 1 时不起作用,while 条件需要考虑step。我的更新版本具有默认 step 值:函数范围(开始,停止,步骤){ step = step || 1 var a=[开始],b=开始; while((b+step)
                      • @daveharris 我在上面添加了一个默认步骤,(step || 1)
                      • 我不得不说,光看它,如果你尝试百万记录,它会让你的电脑崩溃。如果没有,请尝试再添加一个零。我认为你不能超过一个超过 8 个零的数字。
                      【解决方案18】:

                      尚未实施!

                      使用新的Number.range proposal(第一阶段):

                      [...Number.range(1, 10)]
                      //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                      

                      【讨论】:

                        【解决方案19】:

                        https://stackoverflow.com/a/49577331/8784402

                        有 Delta/Step

                        最小的单线
                        [...Array(N)].map((_, i) => from + i * step);
                        

                        示例和其他替代方法

                        [...Array(10)].map((_, i) => 4 + i * 2);
                        //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
                        
                        Array.from(Array(10)).map((_, i) => 4 + i * 2);
                        //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
                        
                        Array.from(Array(10).keys()).map(i => 4 + i * 2);
                        //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
                        
                        [...Array(10).keys()].map(i => 4 + i * -2);
                        //=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
                        
                        Array(10).fill(0).map((_, i) => 4 + i * 2);
                        //=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
                        
                        Array(10).fill().map((_, i) => 4 + i * -2);
                        //=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
                        
                        范围函数
                        const range = (from, to, step) =>
                          [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
                        
                        range(0, 9, 2);
                        //=> [0, 2, 4, 6, 8]
                        
                        // can also assign range function as static method in Array class (but not recommended )
                        Array.range = (from, to, step) =>
                          [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
                        
                        Array.range(2, 10, 2);
                        //=> [2, 4, 6, 8, 10]
                        
                        Array.range(0, 10, 1);
                        //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                        
                        Array.range(2, 10, -1);
                        //=> []
                        
                        Array.range(3, 0, -1);
                        //=> [3, 2, 1, 0]
                        
                        作为迭代器
                        class Range {
                          constructor(total = 0, step = 1, from = 0) {
                            this[Symbol.iterator] = function* () {
                              for (let i = 0; i < total; yield from + i++ * step) {}
                            };
                          }
                        }
                        
                        [...new Range(5)]; // Five Elements
                        //=> [0, 1, 2, 3, 4]
                        [...new Range(5, 2)]; // Five Elements With Step 2
                        //=> [0, 2, 4, 6, 8]
                        [...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
                        //=>[10, 8, 6, 4, 2]
                        [...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
                        //=> [-10, -12, -14, -16, -18]
                        
                        // Also works with for..of loop
                        for (i of new Range(5, -2, 10)) console.log(i);
                        // 10 8 6 4 2
                        
                        仅作为发电机
                        const Range = function* (total = 0, step = 1, from = 0) {
                          for (let i = 0; i < total; yield from + i++ * step) {}
                        };
                        
                        Array.from(Range(5, -2, -10));
                        //=> [-10, -12, -14, -16, -18]
                        
                        [...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
                        //=> [-10, -12, -14, -16, -18]
                        
                        // Also works with for..of loop
                        for (i of Range(5, -2, 10)) console.log(i);
                        // 10 8 6 4 2
                        
                        // Lazy loaded way
                        const number0toInf = Range(Infinity);
                        number0toInf.next().value;
                        //=> 0
                        number0toInf.next().value;
                        //=> 1
                        // ...
                        

                        From-To with steps/delta

                        使用迭代器
                        class Range2 {
                          constructor(to = 0, step = 1, from = 0) {
                            this[Symbol.iterator] = function* () {
                              let i = 0,
                                length = Math.floor((to - from) / step) + 1;
                              while (i < length) yield from + i++ * step;
                            };
                          }
                        }
                        [...new Range2(5)]; // First 5 Whole Numbers
                        //=> [0, 1, 2, 3, 4, 5]
                        
                        [...new Range2(5, 2)]; // From 0 to 5 with step 2
                        //=> [0, 2, 4]
                        
                        [...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
                        //=> [10, 8, 6]
                        
                        使用生成器
                        const Range2 = function* (to = 0, step = 1, from = 0) {
                          let i = 0,
                            length = Math.floor((to - from) / step) + 1;
                          while (i < length) yield from + i++ * step;
                        };
                        
                        [...Range2(5, -2, 10)]; // From 10 to 5 with step -2
                        //=> [10, 8, 6]
                        
                        let even4to10 = Range2(10, 2, 4);
                        even4to10.next().value;
                        //=> 4
                        even4to10.next().value;
                        //=> 6
                        even4to10.next().value;
                        //=> 8
                        even4to10.next().value;
                        //=> 10
                        even4to10.next().value;
                        //=> undefined
                        

                        对于打字稿

                        class _Array<T> extends Array<T> {
                          static range(from: number, to: number, step: number): number[] {
                            return Array.from(Array(Math.floor((to - from) / step) + 1)).map(
                              (v, k) => from + k * step
                            );
                          }
                        }
                        _Array.range(0, 9, 1);
                        

                        https://stackoverflow.com/a/64599169/8784402

                        使用单行生成字符列表

                        const charList = (a,z,d=1)=>(a=a.charCodeAt(),z=z.charCodeAt(),[...Array(Math.floor((z-a)/d)+1)].map((_,i)=>String.fromCharCode(a+i*d)));
                        
                        console.log("from A to G", charList('A', 'G'));
                        console.log("from A to Z with step/delta of 2", charList('A', 'Z', 2));
                        console.log("reverse order from Z to P", charList('Z', 'P', -1));
                        console.log("from 0 to 5", charList('0', '5', 1));
                        console.log("from 9 to 5", charList('9', '5', -1));
                        console.log("from 0 to 8 with step 2", charList('0', '8', 2));
                        console.log("from α to ω", charList('α', 'ω'));
                        console.log("Hindi characters from क to ह", charList('क', 'ह'));
                        console.log("Russian characters from А to Я", charList('А', 'Я'));
                        对于打字稿
                        const charList = (p: string, q: string, d = 1) => {
                          const a = p.charCodeAt(0),
                            z = q.charCodeAt(0);
                          return [...Array(Math.floor((z - a) / d) + 1)].map((_, i) =>
                            String.fromCharCode(a + i * d)
                          );
                        };
                        

                        【讨论】:

                        • 我会说相当全面
                        • 全部 - 请阅读并投票。到目前为止,它应该是最佳答案。
                        【解决方案20】:

                        一种可以双向工作的衬垫:

                        const range = (a,b)=>Array(Math.abs(a-b)+1).fill(a).map((v,i)=>v+i*(a>b?-1:1));
                        

                        见效:

                        const range = (a,b) => Array(Math.abs(a-b)+1).fill(a).map((v,i)=>v+i*(a>b?-1:1));
                        
                        console.log(range(1,4));
                        console.log(range(4,1));

                        【讨论】:

                          【解决方案21】:
                          Array.range = function(a, b, step){
                              var A = [];
                              if(typeof a == 'number'){
                                  A[0] = a;
                                  step = step || 1;
                                  while(a+step <= b){
                                      A[A.length]= a+= step;
                                  }
                              }
                              else {
                                  var s = 'abcdefghijklmnopqrstuvwxyz';
                                  if(a === a.toUpperCase()){
                                      b = b.toUpperCase();
                                      s = s.toUpperCase();
                                  }
                                  s = s.substring(s.indexOf(a), s.indexOf(b)+ 1);
                                  A = s.split('');        
                              }
                              return A;
                          }
                              
                              
                          Array.range(0,10);
                          // [0,1,2,3,4,5,6,7,8,9,10]
                              
                          Array.range(-100,100,20);
                          // [-100,-80,-60,-40,-20,0,20,40,60,80,100]
                              
                          Array.range('A','F');
                          // ['A','B','C','D','E','F')
                              
                          Array.range('m','r');
                          // ['m','n','o','p','q','r']
                          

                          【讨论】:

                          • 你真的不应该在 Array 原型上使用 jerry-rig 方法。
                          • 此方法仅适用于整数和字符。如果参数为null、undefined、NaN、boolean、array、object等,该方法返回如下错误:undefined method toUpperCase to etc!
                          • ``` if (typeof from !== 'number' && typeof from !== 'string') { throw new TypeError('第一个参数应该是数字或字符') } if (typeof to !== 'number' && typeof to !== 'string') { throw new TypeError('第一个参数应该是数字或字符') } ```
                          • 正如 miike3459 所写,如果有一天 Array.range 被添加到标准库中,您可能会遇到严重问题。
                          【解决方案22】:

                          对于数字,你可以使用 ES6 Array.from()which works in everything these days,IE 除外:

                          短版:

                          Array.from({length: 20}, (x, i) => i);
                          

                          加长版:

                          Array.from(new Array(20), (x, i) => i);​​​​​​
                          

                          创建一个从 0 到 19 的数组。这可以进一步缩短为以下形式之一:

                          Array.from(Array(20).keys());
                          // or
                          [...Array(20).keys()];
                          

                          也可以指定上下限,例如:

                          Array.from(new Array(20), (x, i) => i + *lowerBound*);
                          

                          更详细地描述这一点的文章:http://www.2ality.com/2014/05/es6-array-methods.html

                          【讨论】:

                          • 第一个例子甚至可以简化为 [...Array(20).keys()]
                          • Array.from() 方法更简洁一些,而且比两者都快:Array(20).fill().map((_, i) =&gt; i)
                          • @Delapouite 太棒了!你应该把它作为一个单独的答案,我会投票给它!这也是this duplicate的完美答案。
                          • @Delapouite @jib 还有这个:Array.from({length: end - start}, (v, k) =&gt; k + start)
                          • @icc97 是的,linters 可能会抱怨,尽管在 JavaScript 中省略了定义为与传递 undefined 相同的函数参数,所以 fill()(没有参数)不是 错误的 本身。该解决方案中不使用填充值,因此如果您愿意,可以使用fill(0) 来保存一些字符。
                          【解决方案23】:
                          Array.from(Array((m - n + 1)), (v, i) => n + i); // m > n and both of them are integers.
                          

                          【讨论】:

                          • 虽然此代码可以解决 OP 的问题,但最好包含关于您的代码如何解决 OP 问题的说明。通过这种方式,未来的访问者可以从您的帖子中学习,并将其应用到他们自己的代码中。 SO 不是编码服务,而是知识资源。此外,高质量、完整的答案更有可能得到支持。这些功能,以及所有帖子都是独立的要求,是 SO 作为一个平台的一些优势,使其与论坛区分开来。您可以编辑以添加其他信息和/或使用源文档补充您的解释。
                          【解决方案24】:

                          Pythonic 风格的方式:

                          range = (start, end, step) => {
                          let arr = []
                          for(let n=start;n<end;n+=(step||1)) arr.push(n)
                          return arr;
                          }
                          

                          【讨论】:

                            【解决方案25】:

                            --- 更新(感谢@lokhmakov 的简化)---

                            另一个使用 ES6 生成器的版本(见伟大的Paolo Moretti answer with ES6 generators):

                            const RANGE = (x,y) => Array.from((function*(){
                              while (x <= y) yield x++;
                            })());
                            
                            console.log(RANGE(3,7));  // [ 3, 4, 5, 6, 7 ]
                            

                            或者,如果我们只需要可迭代,那么:

                            const RANGE_ITER = (x,y) => (function*(){
                              while (x <= y) yield x++;
                            })();
                            
                            for (let n of RANGE_ITER(3,7)){
                              console.log(n);
                            }
                            
                            // 3
                            // 4
                            // 5
                            // 6
                            // 7
                            

                            --- 原始代码是:---

                            const RANGE = (a,b) => Array.from((function*(x,y){
                              while (x <= y) yield x++;
                            })(a,b));
                            

                            const RANGE_ITER = (a,b) => (function*(x,y){
                              while (x <= y) yield x++;
                            })(a,b);
                            

                            【讨论】:

                            • const range = (x, y) =&gt; Array.from(function* () { while (x &lt;= y) yield x++; }())
                            • @lok​​hmakov 是的,你是对的。谢谢!刚刚在我的答案中应用了您的代码。
                            • 这个应该被认为是优先考虑可迭代解决方案的答案。尤其是对于大范围,这种方法更快并且节省空间。
                            【解决方案26】:

                            数字

                            [...Array(5).keys()];
                             => [0, 1, 2, 3, 4]
                            

                            字符迭代

                            String.fromCharCode(...[...Array('D'.charCodeAt(0) - 'A'.charCodeAt(0) + 1).keys()].map(i => i + 'A'.charCodeAt(0)));
                             => "ABCD"
                            

                            迭代

                            for (const x of Array(5).keys()) {
                              console.log(x, String.fromCharCode('A'.charCodeAt(0) + x));
                            }
                             => 0,"A" 1,"B" 2,"C" 3,"D" 4,"E"
                            

                            作为函数

                            function range(size, startAt = 0) {
                                return [...Array(size).keys()].map(i => i + startAt);
                            }
                            
                            function characterRange(startChar, endChar) {
                                return String.fromCharCode(...range(endChar.charCodeAt(0) -
                                        startChar.charCodeAt(0), startChar.charCodeAt(0)))
                            }
                            

                            作为类型化函数

                            function range(size:number, startAt:number = 0):ReadonlyArray<number> {
                                return [...Array(size).keys()].map(i => i + startAt);
                            }
                            
                            function characterRange(startChar:string, endChar:string):ReadonlyArray<string> {
                                return String.fromCharCode(...range(endChar.charCodeAt(0) -
                                        startChar.charCodeAt(0), startChar.charCodeAt(0)))
                            }
                            

                            lodash.js _.range() 函数

                            _.range(10);
                             => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                            _.range(1, 11);
                             => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                            _.range(0, 30, 5);
                             => [0, 5, 10, 15, 20, 25]
                            _.range(0, -10, -1);
                             => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
                            String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1));
                             => "ABCD"
                            

                            没有库的旧的非 es6 浏览器:

                            Array.apply(null, Array(5)).map(function (_, i) {return i;});
                             => [0, 1, 2, 3, 4]
                            

                            console.log([...Array(5).keys()]);

                            (ES6 归功于 nils petersohn 和其他评论者)

                            【讨论】:

                            • 因为如果它在任何地方都有用,那么它可能在 JS 中也很有用。 (JS 可以做函数式编程类型的东西,这可以从 range(0 语句。这和其他一千个原因在某些半罕见的情况下可能有用)中受益)
                            • 知道为什么简单地使用(new Array(5)).map(function (value, index) { return index; }) 不起作用吗?这会在 Chrome DevTools 中为我返回 [undefined × 5]
                            • @Lewis 因为用它定义的数组有 empty 个插槽,不会被 map() 或其朋友之一迭代。
                            • Array.from(Array(5).keys())
                            • Array(5).fill() 也是可映射的
                            【解决方案27】:

                            我刚刚通过Object.definePropertyArray 上创建了这个polyfill,为整数或字符串创建一个范围。 Object.defineProperty 是一种更安全的创建 polyfill 的方法。

                            更安全的 polyfill

                            if (!Array.range) {
                              Object.defineProperty(Array, 'range', {
                                value: function (from, to, step) {
                                  if (typeof from !== 'number' && typeof from !== 'string') {
                                    throw new TypeError('The first parameter should be a number or a character')
                                  }
                            
                                  if (typeof to !== 'number' && typeof to !== 'string') {
                                    throw new TypeError('The second parameter should be a number or a character')
                                  }
                            
                                  var A = []
                                  if (typeof from === 'number') {
                                    A[0] = from
                                    step = step || 1
                                    while (from + step <= to) {
                                      A[A.length] = from += step
                                    }
                                  } else {
                                    var s = 'abcdefghijklmnopqrstuvwxyz'
                                    if (from === from.toUpperCase()) {
                                      to = to.toUpperCase()
                                      s = s.toUpperCase()
                                    }
                                    s = s.substring(s.indexOf(from), s.indexOf(to) + 1)
                                    A = s.split('')
                                  }
                                  return A
                                }
                              })
                            } else {
                              var errorMessage = 'DANGER ALERT! Array.range has already been defined on this browser. '
                              errorMessage += 'This may lead to unwanted results when Array.range() is executed.'
                              console.log(errorMessage)
                            }
                            

                            示例

                            Array.range(1, 3)
                            
                            // Return: [1, 2, 3]
                            
                            Array.range(1, 3, 0.5)
                            
                            // Return: [1, 1.5, 2, 2.5, 3]
                            
                            Array.range('a', 'c')
                            
                            // Return: ['a', 'b', 'c']
                            
                            Array.range('A', 'C')
                            
                            // Return: ['A', 'B', 'C']
                            
                            Array.range(null)
                            Array.range(undefined)
                            Array.range(NaN)
                            Array.range(true)
                            Array.range([])
                            Array.range({})
                            Array.range(1, null)
                            
                            // Return: Uncaught TypeError: The X parameter should be a number or a character
                            

                            【讨论】:

                            • 修改Array等任何内置对象都是不明智的
                            • @JonKoops 你能解释一下原因吗?
                            • @JonKoops 这段代码不会简单地停止工作,而是完全相反:一旦停止工作,它就会让开发人员知道。我们甚至可以在 Sentry 停止工作时(例如)在测试环境中使用它的报告,以便立即将此问题告知开发人员并防止错误。而如果它停止工作,解决方法也很简单,速度很快,只需要更改函数名并替换它,让它再次工作。
                            • 额外检查typeof from === typeof to
                            【解决方案28】:

                            为了在任一给定数字可能更大的情况下工作,我写了这个:

                            function getRange(start, end) {
                              return Array.from({
                                length: 1 + Math.abs(end - start)
                              }, (_, i) => end > start ? start + i : start - i);
                            }
                            

                            【讨论】:

                              【解决方案29】:

                              保持简单:

                              // Generator
                              function* iter(a, b, step = 1) {
                                for (let i = b ? a : 0; i < (b || a); i += step) {
                                  yield i
                                }
                              }
                              
                              const range = (a, b, step = 1) =>
                                typeof a === 'string'
                                  ? [...iter(a.charCodeAt(), b.charCodeAt() + 1)].map(n => String.fromCharCode(n))
                                  : [...iter(a, b, step)]
                              
                              range(4) // [0, 1, 2, 3]
                              range(1, 4) // [1, 2, 3]
                              range(2, 20, 3) // [2, 5, 8, 11, 14, 17]
                              range('A', 'C') // ['A', 'B', 'C']
                              

                              【讨论】:

                              • .fromCharCode() 的智能解决方案。
                              【解决方案30】:

                              具有定义硬 int 的范围有大量答案,但如果您不知道该步骤,而想要中间有多个步骤怎么办?

                              我为此编写了这段代码。这是不言自明的。

                              const stepScale = (min, max, numberOfSteps) => {
                                const _numberOfSteps = numberOfSteps - 1
                                const scaleBy = (max - min) / _numberOfSteps
                              
                                const arr = []
                                for (let i = 0; i <= _numberOfSteps; i += 1) {
                                  arr.push(min + scaleBy * i)
                                }
                                return arr
                              }
                              
                              export default stepScale
                              
                              stepScale(5, 10, 4)
                              // [5, 6.666666666666667, 8.333333333333334, 10]
                              

                              npm https://npm.im/@universalstandard/step-scale

                              【讨论】:

                                猜你喜欢
                                • 2022-08-02
                                • 1970-01-01
                                • 2019-02-21
                                • 1970-01-01
                                • 2020-09-29
                                • 1970-01-01
                                • 2011-05-31
                                • 1970-01-01
                                相关资源
                                最近更新 更多