arr = []가 arr = new Array보다 빠른 이유는 무엇입니까?


146

이 코드를 실행하고 아래 결과를 얻었습니다. 왜 []더 빠른지 궁금합니다 .

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
  • 사용 []: 299ms
  • 사용 new: 363ms

Raynos 덕분 에이 코드 의 벤치 마크 와 변수를 정의하는 더 가능한 방법이 있습니다.

여기에 이미지 설명을 입력하십시오


5
당신은 jsperf에 관심이있을 수 있습니다 .
뾰족한


새로운 키워드를 주목하십시오. 이것은 "효율적이지 않아야합니다"를 의미합니다. 그것은 말이되지 않으며 최적화를 시도하는 대신 브라우저가 정상적인 인스턴스화를 수행해야합니다.
beatgammit

2
@kinakuta no. 둘 다 같지 않은 새로운 객체를 만듭니다. 나는 의미 []에 equivelent되는 new Array()형태로 표현, 소스 코드의 관점에서 반환 객체하지
Raynos

1
별로 중요하지 않습니다. 그러나 나는 알고 싶다.
Mohsen

답변:


195

이전 답변에 대한 추가 확장 ...

일반적인 컴파일러 관점에서 VM 별 최적화는 무시합니다.

먼저 코드를 토큰 화하는 어휘 분석 단계를 거칩니다.

예를 들어, 다음 토큰이 생성 될 수 있습니다.

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

더 많은 (또는 적은) 처리가 필요한지 이해할 수 있도록 충분한 시각화가 제공되기를 바랍니다.

  1. 위의 토큰을 기반으로 ARRAY_INIT가 항상 배열을 생성한다는 사실을 알고 있습니다. 따라서 단순히 배열을 만들어 채 웁니다. 애매 모호한 한 어휘 분석 단계에서는 ARRAY_INIT와 객체 속성 접근 자 (예 :) obj[foo]또는 문자열 / 정규 리터럴 (예 : "foo [] bar"또는 / [] /)과 괄호 를 이미 구분했습니다.

  2. 이것은 아주 작은 것이지만에 더 많은 토큰이 new Array있습니다. 게다가, 우리는 단순히 배열을 만들고 싶어한다는 것이 아직 명확하지 않습니다. 우리는 "새로운"토큰을 볼 수 있지만 "새로운"토큰은 무엇입니까? 우리는 새로운 "배열"을 원한다는 것을 나타내는 IDENTIFIER 토큰을 볼 수 있지만, JavaScript VM은 일반적으로 IDENTIFIER 토큰과 "네이티브 글로벌 객체"에 대한 토큰을 구별하지 않습니다. 따라서...

  3. IDENTIFIER 토큰이 발생할 때마다 스코프 체인을 찾아야합니다. Javascript VM에는 "인수"개체, 로컬로 정의 된 변수 등을 포함 할 수있는 각 실행 컨텍스트에 대한 "활성화 개체"가 포함되어 있습니다. 활성화 개체에서 찾을 수없는 경우 전역 범위에 도달 할 때까지 범위 체인을 찾기 시작합니다. . 아무것도 발견되지 않으면을 던집니다 ReferenceError.

  4. 변수 선언을 찾았 으면 생성자를 호출합니다. new Array암시 적 함수 호출이며 경험에 따르면 일반적으로 정적 C / C ++ 컴파일러가 "함수 인라이닝"을 허용하는 이유는 스파이더 몽키와 같은 JS JIT 엔진이 즉석에서 수행해야하는 이유입니다.

  5. Array생성자는 오버로드됩니다. Array 생성자는 기본 코드로 구현되므로 성능이 약간 향상되었지만 인수 길이를 확인하고 그에 따라 조치를 취해야합니다. 또한 하나의 인수 만 제공되는 경우 인수 유형을 추가로 확인해야합니다. new Array ( "foo")는 [ "foo"]를 생성합니다. 여기서 new Array (1)은 [정의되지 않음]을 생성합니다

따라서 모든 것을 단순화하기 위해 : 배열 리터럴을 사용하면 VM은 배열이 필요하다는 것을 알고 있습니다. 과 new Array의 VM은 무엇을 알아 내기 위해 여분의 CPU 사이클을 사용할 필요가 new Array 실제로 않습니다.


a = new Array (1000); for (0 ~ 999) {a [i] = i}보다 a = []; for (0 ~ 999) {a [i] = i}보다 빠름 그래도 할당 오버 헤드?
Y. Yoshii

테스트 케이스를 만들었습니다. 새 Array (n)은 빠르게 앞서 시간의 배열의 크기를 알고 경우입니다 jsperf.com/square-braces-vs-new-array을
Y. 요시이

27

가능한 한 가지 이유는 new Array이름 조회 가 필요 Array하지만 (범위에 해당 이름의 변수가있을 수 있음) []그렇지 않습니다.


4
인수 확인도 도움이 될 수 있습니다.
Leonid

Array하나의 인수 len와 여러 인수를 제외 하고. 어디으로 []만 여러 인수를 받아들입니다. 또한 파이어 폭스 테스트는 거의 차이가 없음을 보여줍니다.
Raynos

나는 그것에 진실이 있다고 생각합니다. IIFE에서 OP의 루프 테스트를 실행 하면 성능에 (상대적으로) 상당한 영향을 미칩니다. 포함 var Array = window.Array하면 new Array테스트 성능이 향상됩니다 .
user113716

이 console.time ( 'more vars new'); 때문에 옳지 않다고 생각합니다. for (var i = 0; i <200000; i ++) {var arr = new Array ()}; console.timeEnd ( 'more vars new'); 더 많은 vars new : 390ms 및이 console.time ( 'more vars new'); var myOtherObject = {}, myOtherArray = []; for (var i = 0; i <200000; i ++) {var arr = new Array ()}; console.timeEnd ( 'more vars new'); 더 많은 vars new : 369ms 같은 시간을 반환
Mohsen

2

좋은 질문. 첫 번째 예를 배열 리터럴이라고합니다. 많은 개발자들 사이에서 배열을 만드는 것이 선호되는 방법입니다. 리터럴이 직접 배열을 만드는 동안 새 Array () 호출의 인수를 확인한 다음 객체를 생성하면 성능 차이가 발생할 수 있습니다.

상대적으로 작은 성능 차이는이 점을 뒷받침합니다. 그런데 Object 및 object literal {}을 사용하여 동일한 테스트를 수행 할 수 있습니다.


1

이것은 어떤 의미가 있습니다

객체 리터럴을 사용하면 많은 기능을 지원하는 코드를 작성할 수 있지만 코드 구현 자에게는 비교적 간단합니다. 생성자를 직접 호출하거나 함수 등에 전달 된 올바른 인수 순서를 유지할 필요가 없습니다.

http://www.dyn-web.com/tutorials/obj_lit.php


1

또한 흥미로운 것은 배열길이를 미리 알고 있다면 (요소는 생성 직후에 추가 될 예정 임) 최근 Chrome 70+에서 지정된 길이배열 생성자를 사용하는 것이 훨씬 빠릅니다 .

  • " 새 배열 ( % ARR_LENGTH % ) "– 100 % (빠름) !

  • " [] "– 160-170 % (느리게)

측정 결과가 포함 된 차트.

테스트는 여기에서 찾을 수 있습니다-https: //jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2

참고 :이 결과는 Chrome v.70 + 에서 테스트되었습니다 . 에서 파이어 폭스 V.70 IE 모두 거의 동일한 변형.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.