이 코드를 실행하고 아래 결과를 얻었습니다. 왜 []
더 빠른지 궁금합니다 .
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
답변
이전 답변에 대한 추가 확장 …
일반적인 컴파일러 관점에서 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)
더 많은 (또는 적은) 처리가 필요한지 이해할 수 있도록 충분한 시각화가 제공되기를 바랍니다.
-
위의 토큰을 기반으로 ARRAY_INIT가 항상 배열을 생성한다는 사실을 알고 있습니다. 따라서 단순히 배열을 만들어 채 웁니다. 애매 모호한 한 어휘 분석 단계에서는 ARRAY_INIT와 객체 속성 접근 자 (예 🙂
obj[foo]
또는 문자열 / 정규 리터럴 (예 : “foo [] bar”또는 / [] /)과 괄호 를 이미 구분했습니다. -
이것은 아주 작은 것이지만에 더 많은 토큰이
new Array
있습니다. 게다가, 우리는 단순히 배열을 만들고 싶어한다는 것이 아직 명확하지 않습니다. 우리는 “새로운”토큰을 볼 수 있지만 “새로운”토큰은 무엇입니까? 우리는 새로운 “배열”을 원한다는 것을 나타내는 IDENTIFIER 토큰을 볼 수 있지만, JavaScript VM은 일반적으로 IDENTIFIER 토큰과 “네이티브 글로벌 객체”에 대한 토큰을 구별하지 않습니다. 따라서… -
IDENTIFIER 토큰이 발생할 때마다 스코프 체인을 찾아야합니다. Javascript VM에는 “인수”개체, 로컬로 정의 된 변수 등을 포함 할 수있는 각 실행 컨텍스트에 대한 “활성화 개체”가 포함되어 있습니다. 활성화 개체에서 찾을 수없는 경우 전역 범위에 도달 할 때까지 범위 체인을 찾기 시작합니다. . 아무것도 발견되지 않으면을 던집니다
ReferenceError
. -
변수 선언을 찾았 으면 생성자를 호출합니다.
new Array
암시 적 함수 호출이며 경험에 따르면 일반적으로 정적 C / C ++ 컴파일러가 “함수 인라이닝”을 허용하는 이유는 스파이더 몽키와 같은 JS JIT 엔진이 즉석에서 수행해야하는 이유입니다. -
Array
생성자는 오버로드됩니다. Array 생성자는 기본 코드로 구현되므로 성능이 약간 향상되었지만 인수 길이를 확인하고 그에 따라 조치를 취해야합니다. 또한 하나의 인수 만 제공되는 경우 인수 유형을 추가로 확인해야합니다. new Array ( “foo”)는 [ “foo”]를 생성합니다. 여기서 new Array (1)은 [정의되지 않음]을 생성합니다
따라서 모든 것을 단순화하기 위해 : 배열 리터럴을 사용하면 VM은 배열이 필요하다는 것을 알고 있습니다. 과 new Array
의 VM은 무엇을 알아 내기 위해 여분의 CPU 사이클을 사용할 필요가 new Array
실제로 않습니다.
답변
가능한 한 가지 이유는 new Array
이름 조회 가 필요 Array
하지만 (범위에 해당 이름의 변수가있을 수 있음) []
그렇지 않습니다.
답변
좋은 질문. 첫 번째 예를 배열 리터럴이라고합니다. 많은 개발자들 사이에서 배열을 만드는 것이 선호되는 방법입니다. 리터럴이 직접 배열을 만드는 동안 새 Array () 호출의 인수를 확인한 다음 객체를 생성하면 성능 차이가 발생할 수 있습니다.
상대적으로 작은 성능 차이는이 점을 뒷받침합니다. 그런데 Object 및 object literal {}을 사용하여 동일한 테스트를 수행 할 수 있습니다.
답변
이것은 어떤 의미가 있습니다
객체 리터럴을 사용하면 많은 기능을 지원하는 코드를 작성할 수 있지만 코드 구현 자에게는 비교적 간단합니다. 생성자를 직접 호출하거나 함수 등에 전달 된 올바른 인수 순서를 유지할 필요가 없습니다.
답변
또한 흥미로운 것은 배열 의 길이를 미리 알고 있다면 (요소는 생성 직후에 추가 될 예정 임) 최근 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 모두 거의 동일한 변형.