在PHP中,您可以。。。

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

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

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


当前回答

根据我的理解:

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);

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

其他回答

这里是一个范围函数的定义,它的行为与Python的范围类型完全相同,只是这个函数不是懒惰的。把它变成发电机应该很容易。

范围构造函数的参数必须是数字。如果省略step参数,则默认为1。如果省略了start参数,则默认为0。如果步骤为零,则会引发错误。

range = (start, stop, step=1) => {
    if(step === 0) throw new Error("range() arg 3 must not be zero");

    const noStart = stop == null;
    stop = noStart ? start : stop;
    start = noStart ? 0 : start;
    const length = Math.ceil(((stop - start) / step));

    return Array.from({length}, (_, i) => (i * step) + start);
}

console.log(range(-10, 10, 2));
//output [Array] [-10,-8,-6,-4,-2,0,2,4,6,8]
console.log(range(10));
// [Array] [0,1,2,3,4,5,6,7,8,9]
console.log(3, 12);
// [Array] [3,4,5,6,7,8,9,10,11]

ES6

使用Array.from(此处为文档):

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

我找到的最接近的是radash图书馆:

import { range } from 'radash'

for (let i of range(1, 5)) {
    console.log(i)
}

请参阅此处的文档:

范围Radash

函数范围(firstNum,lastNum){let rangeList=[];如果(firstNum>lastNum){return console.error(“第一个数字不能大于最后一个数字”);}让counter=firstNum;while(计数器<=lastNum){rangeList.push(计数器);计数器++;}返回范围列表;}

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

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]);
        })
    })
})