在PHP中,您可以。。。

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

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

JavaScript本机是否有内置的功能?如果没有,我将如何实施?


当前回答

// range()              0..10, step=1
// range(max)           0..max, step=1
// range(min,max)       min..max, step=1
// range(min,step,max)  min..max, step=step
// Use:
// console.log(...range(3));
// Array.from(range(5))
// [...range(100)]
// for (const v of range(1,10)) { ... 

function* range(...args) {
    let [min, step, max] = {
        0: [0, 1, 10],
        1: [0, args[0] >= 0 ? 1 : -1, args[0]],
        2: [args[0], args[1] >= args[0] ? 1 : -1, args[1]],
        3: args,
    }[args.length] || [];
    if (min === undefined) throw new SyntaxError("Too many arguments");
    let x = min;
    while (step >= 0 ? x < max : x > max) {
        yield x;
        x += step
    }
}
console.log(...range());      // 0 1 2 3 4 5 6 7 8 9
console.log(...range(3));     // 0 1 2
console.log(...range(2, 5));  // 2 3 4
console.log(...range(5, 2));  // 5 4 3
console.log(...range(3, -3)); // 3 2 1 0 -1 -2
console.log(...range(-3, 3)); // -3 -2 -1 0 1 2
console.log(...range(-5, -2));// -5 -4 -3
console.log(...range(-2, -5));// -2 -3 -4

其他回答

没有一个示例进行了测试,每个步骤都有一个生成递减值的选项。

export function range(start = 0, end = 0, step = 1) {
    if (start === end || step === 0) {
        return [];
    }

    const diff = Math.abs(end - start);
    const length = Math.ceil(diff / step);

    return start > end
        ? Array.from({length}, (value, key) => start - key * step)
        : Array.from({length}, (value, key) => start + key * step);

}

测验:

import range from './range'

describe('Range', () => {
    it('default', () => {
        expect(range()).toMatchObject([]);
    })

    it('same values', () => {
        expect(range(1,1)).toMatchObject([]);
    })

    it('step=0', () => {
        expect(range(0,1,0)).toMatchObject([]);
    })

    describe('step=1', () => {
        it('normal', () => {
            expect(range(6,12)).toMatchObject([6, 7, 8, 9, 10, 11]);
        })

        it('reversed', () => {
            expect(range(12,6)).toMatchObject([12, 11, 10, 9, 8, 7]);
        })
    })

    describe('step=5', () => {

        it('start 0 end 60', () => {
            expect(range(0, 60, 5)).toMatchObject([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]);
        })

        it('reversed start 60 end -1', () => {
            expect(range(55, -1, 5)).toMatchObject([55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0]);
        })
    })
})

如果您只想使用范围来重复一个过程n次,您可以简单地使用此代码

[...Array(10)].map((item, index) => ( 
    console.log("item:", index)
))

这个也反过来。

const range = ( a , b ) => Array.from( new Array( b > a ? b - a : a - b ), ( x, i ) => b > a ? i + a : a - i );

range( -3, 2 ); // [ -3, -2, -1, 0, 1 ]
range( 1, -4 ); // [ 1, 0, -1, -2, -3 ]

一个定义了硬整数的范围有很多答案,但是如果你不知道这一步,而你想在这一步之间多走几步呢?

我写这段代码就是为了做到这一点。这很不言自明。

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]

对于npmhttps://npm.im/@通用标准/步长

根据我的理解:

JS的运行时环境不支持尾部调用优化。编写任何递归函数来生成一个大范围的函数都会给你带来麻烦。如果我们要处理大量数据,那么创建循环数组可能不是最好的做法。写入大循环会导致事件队列变慢。


function range(start, end, step = 1) {
  const _range = _start => f => {
    if (_start < end) {
      f(_start);
      setTimeout(() => _range(_start + step)(f), 0);
    }
  }

  return {
    map: _range(start),
  };
}

range(0, 50000).map(console.log);

此函数不会引发上述问题。