2014-11-30 5 views
1

Array.forEach 중간에 배열을 삽입해야했습니다. JavaScript가 이러한 상황을 어떻게 처리하는지 확인하고 싶었습니다. 나는 무한 루프를 포함하여 무엇이든 기대했다. 그러나 결과는 저에게 아주 이상합니다. 여기서 무슨 일이 일어나고 있는지 설명 할 수 :forEach 내에서 배열 수정

var A = [0, 1, 2, 3, 4, 5, 6, 7] 
 
A.forEach(function(x) { 
 
    if (x == 3) A.splice(1, 0, 'new') 
 
}) 
 
document.write(JSON.stringify(A))

+2

Array.forEach''의 알고리즘 [언어 명세 (가능하다 http://www.ecma-international.org/ecma-262/5.1/# 초 15.4.4.18). (또는 JS에서 확인하려면 [Polyfill at MDN] (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill)을 확인하십시오.) – nnnnnn

답변

3

을 중간 writeln의 많이 관찰에서 :

forEach 루프가 한 번만 각 원래 인덱스에 보이는
  1. - 배열의 길이를 임시 변수에 저장 했어야합니다.

  2. splice 라인은 동일한 위치에 "new"를 삽입합니다. 첫 번째 요소 뒤에 "new"가 삽입됩니다.

  3. 이것은 네 번째 위치에서 "3"을 본 후에 발생합니다.

    [ 0, "new", 1, 2, 3, 4, 5, 6, 7 ] 
    

    을하고 forEach 반복자는 요소 (4)에있다 - 다시 "3"입니다 :

  4. 그래서 3 번째 반복에서, 첫 번째 삽입 후, 배열은 다음과 같습니다.

  5. .. 배열 길이의 나머지 부분에 대해 "new"가 삽입됩니다.

루프 코드 작성자는 뒤에서 배열을 변경하는 사람을 고려해야합니다. 약간 더 안전한 방법은 원본 배열의 사본을 만들 수 있었을 수도 있지만 의 내용이 깊은 사본이 필요합니다. (변경이 얼마나 진행될 지 미리 알 수는 없지만) 최후의 경우 인 것처럼 보이기 위해 많은 복사 작업이 필요합니다.

3

예상되는 동작과 실제 루프가 아니지만 비생산적인 루프입니다.

현재 색인 앞에 요소를 추가하고 있습니다. 이렇게하면 현재 값이 이동하므로 각 반복에서 x == 3이 시작됩니다.

이것은 끝없는 루프를위한 전제이지만 JS forEach는 천장을 그 천장에 붙이고 천장은 원래 배열에있는 요소의 수입니다. 배열을 조작하는 방법에 관계없이 원래의 길이 인 8 번 이상 실행할 수 없습니다.

이 코드의 출력은 무슨 일이 일어나고 있는지 가장 잘 보여줍니다

:

var A = [0, 1, 2, 3, 4, 5, 6, 7] 
    A.forEach(function(x, index) { 
    document.writeln('A[' + index + '] = ' + x + '<br/>'); 
    if (x == 3) { 
     A.splice(1, 0, 'new') 
    } 
    }) 
    document.write(JSON.stringify(A)); 

출력 :

A[0] = 0 
A[1] = 1 
A[2] = 2 
A[3] = 3 
A[4] = 3 
A[5] = 3 
A[6] = 3 
A[7] = 3 
[0,"new","new","new","new","new",1,2,3,4,5,6,7] 
+1

_ "그래서 실제로 무한 루프로 끝납니다. "- 당신은하지 않습니다. '.forEach()'메쏘드의 알고리즘은 루핑되기 전에 배열의 원래 길이를 기록하고 그 길이보다 작은 정의 된 각 인덱스에 대해 콜백을 호출하도록 명시 적으로 정의됩니다. – nnnnnn

+0

우리는 여기서 의미론에 대해 논쟁하고 있습니다. 무한 루프는 비생산적인 루프로 정의 될 수도 있습니다. while (true) {} 루프는 메모리가 부족할 때 끝나기 때문에 끝이 없습니다. –

+1

아니, 단지 의미론이 아닙니다. 무한 루프는 근본적으로 끝나지 않고 런타임 환경에 의해 중지 될 수도 있고 중단되지 않을 수도있는 "영원히"실행되는 것과 같은 최종 조건이 결코 충족되지 않는 루프입니다. while (true) {}'는 각 반복마다 추가 메모리가 필요하지 않기 때문에 메모리가 부족하지 않습니다. '.forEach()'알고리즘의 종료 조건은 주어진 반복에서 배열을 조작하는 방법에 상관없이 충족되므로 "무한"의 정의를 충족시키지 않습니다. – nnnnnn

1

좋아, 그래서이 단계에서 그것을 할 수 있습니다 : 일반적으로

  1. 루프 반복 요소 "3"까지

  2. 요소 "3"에서 배열의 첫 번째 위치에 "new"를 지나면 [0, 신, 1, 2, 3, 4, 5, 6]과 같은 루프가 반복되지만 모든 요소는 이동 중입니다. 오른쪽의 한 위치에서 루프의 다음 반복에서 네 번째 요소가 이동 되었기 때문에 다시 "3"이됩니다.

  3. 그는 마지막 8 번째 요소까지 2 단계를 반복하고 4 번 이상 배열의 첫 번째 위치에 "new"를 넣습니다. 당신이 "새로운"붙여 넣을 경우 한 시간이 그래서 좋아합니까 :

    A.forEach (기능 (X) {
    (X == 3) {A.splice (1, 0, '새로운'경우) 체류;}} )