javascript에서 foreach를 수행 할 때 배열의 값을 변경할 수 있습니까?


300

예:

var arr = ["one","two","three"];

arr.forEach(function(part){
  part = "four";
  return "four";
})

alert(arr);

배열은 여전히 ​​원래 값을 가지고 있습니다. 반복 함수에서 배열의 요소에 액세스 할 수있는 방법이 있습니까?



map ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )을 시도해보십시오 :x=[2,3,4]; x=x.map(n=>n*2); // [4,6,8]
Justin

답변:


468

콜백에는 요소, 인덱스 및 배열 자체가 전달됩니다.

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

편집 -주석에서 언급했듯이 .forEach()함수는 두 번째 인수를 취할 수 this있으며 콜백에 대한 각 호출 의 값으로 사용됩니다 .

arr.forEach(function(part, index) {
  this[index] = "hello world";
}, arr); // use arr as this

그 두 번째 예제 프로그램 arr자체로 설정되고 thiscallback.One에서은에 포함 된 배열을 생각할 수 있습니다 .forEach()통화가 될 수있는 기본this이지만 그렇지 않은 어떤 이유로,; this될 것입니다 undefined그 두 번째 인수가 제공되지 않은 경우.

(참고 : this콜백이 =>함수 인 경우 위의 내용은 적용되지 않습니다 . 왜냐하면 this그러한 함수가 호출 될 때 아무것도 바인딩되지 않기 때문 입니다.)

또한 Array 프로토 타입에 제공되는 유사한 유틸리티가 모두 있다는 점을 기억하는 것이 중요하며, 최상의 솔루션으로 다른 툴을 선택하는 것이 가장 좋습니다. 당신이있어:

  • forEach 배열의 모든 항목에 대해 또는 모든 항목에 대해 수행
  • filter 적격 항목 만 포함하는 새 배열을 생성하기 위해;
  • map 기존 배열을 변환하여 일대일 새로운 배열을 만들기 위해;
  • some 배열의 적어도 하나의 요소가 어떤 설명에 맞는지 확인하기 위해;
  • every배열의 모든 항목이 설명과 일치 하는지 확인합니다 .
  • find 배열에서 값을 찾기 위해

등등. MDN 링크


34
감사! ES6 : arr.forEach ((o, i, a) => a [i] = myNewVal)
DiegoRBaquero

part(또는 심지어 oes6 에서도 ) 정의되지 않습니까? 반복되는 가치를 얻는 방법?
다닐 Mashkin

@DaniilMashkin partundefined배열의 요소가 undefined명시 적 으로 할당 된 경우입니다. 배열의 "빈"슬롯 (값이 할당되지 않은 배열 항목)은 .forEach()대부분의 다른 배열 반복 방법으로 건너 뜁니다 .
Pointy

2
완성도 를 높이려면 콜백 내부에서 사용할 수 .forEach()있는 두 번째 인수가 필요합니다 . 참고 : 이것은 콜백 의 인수가 아닌 인수입니다. thisArgthis.forEach
전능 한 낙타 Moha

3
this전달 된 두 번째 인수로 를 사용하려면 ES6의 화살표 함수를 .forEach()사용하면 컨텍스트가 바인딩되지 않으므로 구문을 사용하여 콜백 함수를 전달해야합니다 . function()() => {}
jpenna

131

의합시다 시도 간단하게하고 실제로 작동하는 방법을 논의하기 위해. 변수 유형 및 함수 매개 변수와 관련이 있습니다.

우리가 이야기하는 코드는 다음과 같습니다.

var arr = ["one","two","three"];

arr.forEach(function(part) {
  part = "four";
  return "four";
})

alert(arr);

먼저 Array.prototype.forEach ()에 대해 읽어야합니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

둘째, JavaScript의 값 유형에 대해 간단히 이야기하겠습니다.

프리미티브 (정의되지 않은, null, 문자열, 부울, 숫자)는 실제 값을 저장합니다.

전의: var x = 5;

참조 유형 (사용자 정의 객체)은 객체의 메모리 위치를 저장합니다.

전의: var xObj = { x : 5 };

셋째, 함수 매개 변수 작동 방식

함수에서 매개 변수는 항상 값으로 전달됩니다.

하므로 arr문자열의 배열이고, 그 배열의 프리미티브 들이 값에 의해 저장되는 수단 개체.

따라서 위의 코드 foreach는 ()가 반복마다 있음이 수단 part과 동일한 값과 같은 arr[index], 하지만 동일한 개체 .

part = "four";part변수 가 변경 되지만 arr홀로 남겨 집니다.

다음 코드는 원하는 값을 변경합니다.

var arr = ["one","two","three"];

arr.forEach(function(part, index) {
  arr[index] = "four";
});

alert(arr);

이제 arrarray가 참조 유형 의 배열 인 경우 참조 유형 은 실제 객체 대신 객체의 메모리 위치를 저장하므로 다음 코드가 작동합니다.

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // part and arr[index] point to the same object
  // so changing the object that part points to changes the object that arr[index] points to

  part.num = "four";
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

다음 part은 객체를 arr단독으로 저장 한 채로 새 객체를 가리 키도록 변경할 수 있음을 보여줍니다 .

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // the following will not change the object that arr[index] points to because part now points at a new object
  part = 5;
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

2
참으로 훌륭한 설명입니다! 다른 반복 방법에서 설명을 확장하는 것이 더 좋았을 것입니다. forEach와 같이 원래 배열을 변경하기 위해 index "가 누락되었습니다. 또한 ES5 맵은 forEach와 비슷해 보일 수 있습니다. 아마도 맵에서 값을 반환 할 가능성이 인덱스를 사용하는 것보다 구문 관점에서 더 명확하게 보일 수 있습니다.
Christophe Vidal

1
좋은 설명입니다. 감사합니다. 결국 나는이 진술을 얻을 수 없습니다 : In functions, parameters are always passed by value. 두 번째 예는 어떻습니까?
Alex

@ 7sides, 그 진술은 함수 매개 변수가 항상 값으로 전달된다는 것을 설명합니다. 따라서 프리미티브의 경우 프리미티브가 가리키는 값이됩니다. 객체의 경우 객체가 가리키는 위치가됩니다. 이 w3schools 페이지 에 좋은 설명이 있습니다. 섹션 참조 인수는 값에 의해 전달되는객체 참조에 의해 전달된다 .
Dave

함수에서 매개 변수는 항상 값으로 전달됩니다. 밤. 고마워. +1
radarbob

92

배열 : [1, 2, 3, 4]
결과 :["foo1", "foo2", "foo3", "foo4"]

Array.prototype.map() 원래 배열 유지

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);

console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );

Array.prototype.forEach() 원래 배열 재정의

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);

console.log( "Overridden: %s", originalArr );


3
"Array.prototype.map () arr 변수를 다시 할당하여 얻은 원래 배열 수정".map ()은 원래 배열을 수정하지 않으며 새 배열을 만듭니다. 변수를 다시 할당해도 원래 객체는 변경되지 않습니다.
vadkou

1
let arr1 = ["1", 2, 3, 4]; arr1.map(function(v) { return "foo"+ v; }); console.log( arr ); Array.prototype.map () 절대로 원래 배열을 수정하지 마십시오.
Anupam Maurya

@AnupamMaurya 그건 사실이 아닙니다. map확실히 배열을 변경할 수 forEach있으며 일반적으로 그렇지 않습니다.
user4642212

@SebastianSimon, 답변 주셔서 감사합니다. 내가 추가하고 싶은 것은 forEach가 데이터를 재정의하지만 맵은 새 사본을 생성 할 수 없다는 것입니다.
Anupam Maurya

14

자바 스크립트 값으로 전달하며, 이는 본질적으로 의미하는 것은 partA는 복사 배열의 값.

값을 변경하려면 루프에서 배열 자체에 액세스하십시오.

arr[index] = 'new value';


part변수가 포인터가 아니라 값이라는 것이 옳더라도-복사 여부 에 따라 다릅니다.
Bergi

8
"자바 스크립트는 값으로 전달됩니다"라고 말하는 것이 총체적인 일반화입니다. JavaScript에는 참조 유형이 있습니다. 값 유형은 값으로 전달됩니다.
Alex Turpin

9
총체적인 일반화가 아닙니다. 완전히 정확하고 절대적인 진술. 자바 스크립트는 값으로 참조를 전달합니다. 자바 스크립트는 항상 가치를 전달합니다.
hvgotcodes

1
@ Bergi : 아니요, 유형은 중요하지 않습니다. 모든 값은 할당시 복사됩니다. JavaScript의 유일한 값은 기본 요소 및 참조입니다. 프리미티브와 참조 모두 할당시 복사됩니다.
newacct September

6
@Bergi 언어가 참조라는 것을 가지고 있다고해서 참조로 전달을 사용하는 것은 아닙니다. 참조는 값으로 전달 될 수 있으며 참조 값이 복사되고 해당 복사본이 인수로 사용됩니다.
hvgotcodes


4

=>스타일 함수 를 사용하는 비슷한 답변이 있습니다.

var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );

결과를 제공합니다.

[11,12,13,14]

self매개 변수 때문에, 화살표 스타일의 기능이 꼭 필요한 것은

data.forEach( (item,i) => data[i] = item + 10);

작동합니다.


3

.forEach 함수는 콜백 함수 (eachelement, elementIndex)를 가질 수 있습니다. 따라서 기본적으로해야 할 일은 다음과 같습니다.

arr.forEach(function(element,index){
    arr[index] = "four";   //set the value  
});
console.log(arr); //the array has been overwritten.

또는 원래 배열을 유지하려면 위의 프로세스를 수행하기 전에 사본을 만들 수 있습니다. 복사하려면 다음을 사용하십시오.

var copy = arr.slice();

3
배열의 사본을 만들려면 map()대신을 사용하십시오 forEach(). map()소스 배열을 반복하고 원본의 [수정 된] 사본을 포함하는 새 배열을 반환합니다. 소스 배열은 변경되지 않습니다.
Nicholas Carey

2

Array 객체 메서드를 사용하면 기본 for 루프와 비교하여 Array 내용을 수정할 수 있지만 이러한 메서드에는 중요한 기능이 하나 없습니다. 실행시 인덱스를 수정할 수 없습니다.

예를 들어 현재 요소를 제거하고 동일한 배열 내의 다른 인덱스 위치에 배치하면 쉽게 수행 할 수 있습니다. 현재 요소를 이전 위치로 이동하면 다음 반복에서 문제가 발생하지 않으며 마치 아무것도하지 않은 것처럼 다음 항목이 동일하게됩니다.

인덱스가 5까지 카운트되면 인덱스 위치 5에서 항목을 인덱스 위치 2로 이동하는이 코드를 고려하십시오.

var ar = [0,1,2,3,4,5,6,7,8,9];
ar.forEach((e,i,a) => {
i == 5 && a.splice(2,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9

그러나 현재 요소를 현재 색인 위치 너머로 이동하면 약간 지저분 해집니다. 그런 다음 바로 다음 항목이 이동 된 항목 위치로 이동하고 다음 반복에서는이를 보거나 평가할 수 없습니다.

인덱스가 5까지 카운트되면 인덱스 위치 5에서 항목을 인덱스 위치 7로 이동하는이 코드를 고려하십시오.

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && a.splice(7,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 7 - 7 5 - 8 8 - 9 9

그래서 우리는 루프에서 6을 결코 만나지 않았습니다. 일반적으로 for 루프에서는 배열 항목을 앞으로 이동할 때 인덱스가 다음 실행에서 동일한 위치에 유지되고 제거 된 항목 위치로 이동 된 항목을 평가할 수 있도록 인덱스 값을 감소시킬 것으로 예상됩니다. 배열 방법으로는 불가능합니다. 색인을 변경할 수 없습니다. 다음 코드를 확인하십시오

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && (a.splice(7,0,a.splice(i,1)[0]), i--);
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 4 5 - 6 7 - 7 5 - 8 8 - 9 9

우리가 감소 i하면 5에서 6까지 계속되지 않고 왼쪽에서 계속됩니다.

따라서 이것을 명심하십시오.


1

복사본을 반복하기 위해 slice ()의 zhujy_8833 제안을 확장하여 색인을 변경하는 요소를 완전히 추가하거나 삭제하려면 이미 삭제하거나 추가 한 요소의 수를 세고 그에 따라 색인을 변경하십시오. 예를 들어, 요소를 삭제하려면 다음을 수행하십시오.

let values = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"];
let count = 0;
values.slice().forEach((value, index) => {
    if (value === "A2" || value === "A5") {
        values.splice(index - count++, 1);
    };
});
console.log(values);

// Expected: [ 'A0', 'A1', 'A3', 'A4', 'A6', 'A7', 'A8' ]

전에 요소를 삽입하려면

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - count--, 0, 'newVal');
};

// Expected: ['newVal', A0, 'A1', 'A2', 'A3', 'A4', 'A5', 'newVal', 'A6', 'A7', 'newVal', 'A8' ]

다음에 요소를 삽입하려면

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - --count, 0, 'newVal');
};

// Expected: ['A0', 'newVal', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'newVal', 'A7', 'A8', 'newVal']

요소를 바꾸려면 :

if (value === "A3" || value === "A4" || value === "A7") {
    values.splice(index, 1, 'newVal');
};

// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]

참고 : 'before'및 'after'삽입을 모두 구현하는 경우 코드는 'before'삽입을 먼저 처리해야합니다. 다른 방법은 예상과 다릅니다.


0

재정의하려면 이것을 시도 할 수 있습니다

var newArray= [444,555,666];
var oldArray =[11,22,33];
oldArray.forEach((name, index) => oldArray [index] = newArray[index]);
console.log(newArray);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.