>  기사  >  웹 프론트엔드  >  js로 배열을 빠르게 초기화하는 방법

js로 배열을 빠르게 초기화하는 방법

一个新手
一个新手원래의
2017-09-09 10:43:042843검색

태그(공백으로 구분): call apply


참고 버전

일반적으로 코드를 작성할 때 배열을 빠르게 초기화해야 하는 경우가 있습니다. 예를 들어 zeros와 유사한 함수가 필요합니다. matlab. 여기에 필요한 경우 하루 24시간을 나타내는 0-23의 배열을 생성합니다. zeros函数,假如这里我们需要生成一个0-23的数组用于表示一天24小时。
最基本的做法如下:

function(){
    let hours = [];    
    for(let k = 0; k < 24; k++ )
    hours.push(k);    
    return hours;
}

下面我们来思考如何用更优雅的方式实现。
考虑使用new Array(24)+ map的方法来实现。
代码如下:

Array(24).map((_, h) => h);

注意,这里map的第二个参数是索引,平时用的少,这里把索引作为数值。
结果与预期并不符合,为啥呢?
简单搜索了一下,发现时因为js里的稀疏数组的逻辑导致的。
我们先看一下下面的代码:

let a = [];
a[1000] = 2;
console.log(a.length);// 1000a.forEach(x => console.log("hello"));// only one "hello"

js的处理逻辑是,对于没有主动赋值的位置进行“空置”处理,对于这些“空置”未知,迭代器是不会理会的,这么做最主要的目的就是避免不合理的赋值操作导致的bug。
假设没有这种逻辑,我们写下了new Array(Date.now()),这将导致系统新建一个非常大的数组,而实际上啥也没存。
我们可以吧new Array(len)干的事情简单理解为下面的过程:

function(len){
    let r = [];
    r.length = len;    
    return r;

这就是为什么对new Array(len)调用map或者forEach的时候跟预期不一致了。
如何解决这一问题呢,除了使用new Array(len)的形式,我们还可以使用new Array(1,2,3)这种写法来初始化数组,但是这么写就没法实现我们编写初始化数组的目的了。
这个时候我们想到了apply,这个函数的第二个参数正好就是一个数组,于是我们写下了下面的代码。

// 借用apply
Array.apply(null, Array(24)).map((_, h) => h);
// [0, 1, ..., 24]

得到了我们希望的结果。这就说明,Array(24)apply中作为参数的时候是被当做24个值对待的,因为这一点就保证了最后得到的数组长度是24。
既然如此,我们当然同样可以使用apply的姊妹函数call

// 借用call
Array.call(null, ...Array(24)).map((_, h) => h);
// [0, 1... 23]

这也更确认了一件事,Array(len)解构会得到len个参数而非一个参数,当然call的使用必须在支持解构操作符的环境中。

在熟悉了callapply的原理后,我们可以进一步写出下面的代码:

// Array本身
Array(...Array(24)).map((_, h) => h);
// [0, 1, ..., 24]

这种形式已经足够优雅了。
另外,在ES6中,Array提供了新方法fill,借用该方法填充那些“空置”位,进而保证后续的操作能顺利进行。
具体代码如下:

// 推荐
Array(24).fill(null).map((_, h) => h);

现在也比较推荐最后一种写法,这种方法也最为直观。
不过需要注意fill가장 기본적인 접근 방식은 다음과 같습니다.

// no-fillconsole.time("no-fill");let t = Array(5e7);console.timeEnd("no-fill");// fillconsole.time("fill");let q = Array(5e7).fill(null);console.timeEnd("fill");// => no-fill: 0.240ms// => fill: 3247.921ms

어떻게 하면 좀 더 우아하게 구현할 수 있을지 생각해 보겠습니다.

이를 달성하려면 new Array(24) + map 메서드를 사용하는 것이 좋습니다.

코드는 다음과 같습니다.
rrreee
여기서 map의 두 번째 매개변수는 인덱스이며 거의 사용되지 않습니다. 여기서 인덱스는 숫자 값으로 사용됩니다. 🎜결과가 기대에 미치지 못하는데요, 이유는 무엇인가요? 🎜간단한 검색 끝에 js의 희소 배열 논리로 인해 발생하는 것으로 나타났습니다. 🎜먼저 다음 코드를 살펴보겠습니다. 🎜rrreee🎜js의 처리 논리는 값이 적극적으로 할당되지 않은 위치에 대한 "공석"을 처리하는 것입니다. 알 수 없는 "공석"에 대해서는 반복자가 처리하지 않습니다. 가장 중요한 것은 불합리한 할당 작업으로 인해 발생하는 버그를 방지하는 것입니다. 🎜그런 논리가 없고 new Array(Date.now())를 작성한다고 가정해 보겠습니다. 그러면 시스템이 매우 큰 배열을 생성하지만 실제로는 아무것도 저장하지 않게 됩니다. 🎜다음 프로세스를 통해 new Array(len)가 수행하는 작업을 간단히 이해할 수 있습니다. 🎜rrreee🎜이것이 new Array(len)에서 map이 호출되는 이유입니다. /code> 또는 <code>forEach가 예상과 일치하지 않습니다. 🎜이 문제를 해결하려면 new Array(len)를 사용하는 것 외에도 new Array(1,2,3)를 사용하여 Array를 초기화할 수도 있습니다. 이 방법으로는 초기화된 배열을 작성하려는 목적을 달성할 수 없습니다. 🎜이때 우리는 apply를 생각했는데 이 함수의 두 번째 매개변수가 배열이여서 다음과 같은 코드를 작성했습니다. 🎜rrreee🎜원하는 결과를 얻었습니다. 이는 apply에서 매개변수로 사용될 때 Array(24)가 24개의 값으로 처리된다는 의미입니다. 이렇게 하면 최종 배열의 길이가 24개가 되도록 보장되기 때문입니다. 🎜이 경우 물론 apply의 자매 함수인 call을 사용할 수도 있습니다. 🎜rrreee🎜이것은 또한 한 가지를 확인합니다. Array(len)의 분해는 하나의 매개변수 대신 len 매개변수를 얻습니다. 물론 call은 필수입니다. 구조 분해 연산자를 지원하는 환경에서 사용됩니다. 🎜🎜호출적용 원칙에 익숙해지면 다음 코드를 더 작성할 수 있습니다. 🎜rrreee🎜이 형식은 충분히 우아합니다. 🎜또한, ES6에서 Array는 새로운 메소드 fill을 제공합니다. 이 메소드는 "빈" 비트를 채워 후속 작업을 보장하는 데 사용할 수 있습니다. 원활하게 업무를 진행할 수 있습니다. 🎜구체적인 코드는 다음과 같습니다. 🎜rrreee🎜이제 마지막 작성 방법도 권장되는데, 이 방법이 가장 직관적이기도 합니다. 🎜그러나 fill 메서드 사용에 주의해야 하며, 블라인드 채우기를 피해야 합니다. 이렇게 하면 js의 "비어 있는" 논리가 설계되었다는 위에서 언급한 버그가 발생할 수 있기 때문입니다. 피하기 위해. 🎜관심 있으신 분은 다음 코드를 시도해 보세요. 🎜rrreee🎜 브라우저에서 시도해 보면 기본적으로 브라우저가 응답하지 않습니다. 결과가 나오지 않는 것을 방지하기 위해 더 큰 값을 설정하지 않았습니다. int가 4바이트의 메모리를 차지한다고 가정하면 이 채우기는 200M의 메모리를 차지하며 5천만 번 반복되어야 합니다. 이는 필연적으로 많은 양의 CPU와 메모리를 차지하게 되며 이는 단일 스레드 js에서는 절대 허용되지 않습니다. 🎜🎜🎜

위 내용은 js로 배열을 빠르게 초기화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.