태그(공백으로 구분): 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
的使用必须在支持解构操作符的环境中。
在熟悉了call
和apply
的原理后,我们可以进一步写出下面的代码:
// 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
메서드를 사용하는 것이 좋습니다.
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!