자바 스크립트 forEach 메소드는 어떤 용도로 사용됩니까 (그 맵은 할 수 없음)?


91

내가 map과 foreach에서 보는 유일한 차이점 map은 배열을 반환하고 forEach그렇지 않다는 것입니다. 그러나 forEach" func.call(scope, this[i], i, this);" 메서드 의 마지막 줄도 이해하지 못합니다 . 예를 들어, "없는 this"및 " scope"동일한 개체 참조되지 않고 this[i]i루프의 현재 값을 참조?

다른 게시물에서 누군가 " forEach목록의 각 요소를 기반으로 무언가를하고 싶을 때 사용 합니다. 예를 들어 페이지에 항목을 추가 할 수 있습니다. 기본적으로"부작용 "을 원할 때 유용합니다. 부작용이 무엇을 의미하는지 모르겠습니다.

Array.prototype.map = function(fnc) {
    var a = new Array(this.length);
    for (var i = 0; i < this.length; i++) {
        a[i] = fnc(this[i]);
    }
    return a;
}

Array.prototype.forEach = function(func, scope) { 
    scope = scope || this; 
    for (var i = 0, l = this.length; i < l; i++) {
        func.call(scope, this[i], i, this); 
    } 
}

마지막으로, 다음과 같이 숫자를 조작하는 것 외에 자바 스크립트에서 이러한 메서드를 실제로 사용하는 것이 있습니까 (데이터베이스를 업데이트하지 않기 때문에) :

alert([1,2,3,4].map(function(x){ return x + 1})); //this is the only example I ever see of map in javascript.

답장을 보내 주셔서 감사합니다.


map및에서 했던 것처럼 네이티브 JavaScript에 대한 함수의 정의를 어떻게 찾을 수 forEach있습니까? Google에서 얻는 것은 사용 사양과 자습서뿐입니다.
WoodrowShigeru

답변:


95

예제에서 map와 의 근본적인 차이점 은 원래 배열 요소에서 작동하는 반면 명시 적으로 새 배열을 결과로 반환한다는 것입니다.forEachforEachmap

forEach변화하는 선택적하고 - - 각 요소를 원래의 배열에 당신이 몇 가지 조치를 취하고있다. 이 forEach메서드는 각 요소에 대해 제공 한 함수를 실행하지만 아무것도 반환하지 않습니다 ( undefined). 반면, map배열을 살펴보고 각 요소에 함수를 적용한 다음 결과를 새 배열로 내 보냅니다 .

"부작용" forEach은 원래 배열이 변경된다는 것입니다. "부작용 없음" map은 관용적 사용법에서 원래 배열 요소가 변경 되지 않음을 의미합니다 . 새 배열은 원래 배열의 각 요소에 대한 일대일 매핑입니다. 매핑 변환은 제공된 함수입니다.

관련된 데이터베이스가 없다는 사실은 결국 어떤 언어로든 프로그래밍의 본질 중 하나 인 데이터 구조를 조작 할 필요가 없다는 것을 의미하지는 않습니다. 마지막 질문에 관해서는 배열에 숫자뿐만 아니라 객체, 문자열, 함수 등이 포함될 수 있습니다.


4
참고 :이 대답은 실제로 말도 안됩니다. 요소 수정을 포함하여 할 .map수있는 모든 작업을 수행 .forEach할 수 있으며 반복기 함수에서 생성 된 새 목록을 반환합니다.
Travis Webb

6
과거의 답변 : 나는 정중하게 동의하지 않습니다. .map()새 배열을 만들고 원본을 변경하지 않습니다. 실제로 매핑되는 배열을 수정할 수는 있지만, 말도 안되는 것은 아니지만 최소한 비관 상적 일 것입니다. .forEach()유사하지만 각 요소에 해당 기능을 적용하지만 항상을 반환합니다 undefined. 위의 모든 사항에도 불구하고 OP는 어레이 프로토 타입에 추가 된 자신의 특정 기능에 대해서도 질문하고 있습니다. 과거에는 ES5가 없었습니다.
Ken Redler 2015 년

4
으로 forEach할 수없는 작업은 아직 없습니다 map. 당신은 단순히 반환 값을 걱정 없습니다 map당신은이있을 것이다 forEach. 차이점은 map결과를 기반으로 새 어레이를 생성하지 않으려는 작업 에 사용하는 것은 매우 비효율적이라는 것 입니다. 따라서이를 위해 forEach.
찌를

2
@poke : .. 그리고 마찬가지로, 평범한 오래된 for루프로 필요한 모든 것을 할 수 있습니다 . 나는 "효과 성"에 약간의 차이가 있다는 것에 동의하지 않는다. 또한 나는 누군가가 다른 사람이 어떻게 든 달성 할 수없는 마법을 가지고 있다고 주장하지 않는다고 생각한다. 실제로 map할 수없는 한 가지가 있지만 배열을 반환하지 않는 것입니다 . JS가 아니라 같은 기능 즐겨 찾기의 행동에 다른 언어의 기대에 부응 가진 가치있다 map, reduce, filter, 등 예, 당신이 구현할 수있는 reduceRight유사한 빌딩 블록을 사용하지만, 왜 그냥 사용하지는 reduceRight?
켄 Redler

1
@ChinotoVokro, 귀하의 예제는 반환 된 객체 내부 에 할당하여 원래 배열을 명시 적으로 변경 하는 b.val = b.val**2 입니다. 그것이 우리가 말하는 정확한 것은 실제로 가능하지만 혼란스럽고 비관 상적입니다. 일반적으로 새 값을 반환하고 원래 배열에도 할당하지 않습니다.a=[{val:1},{val:2},{val:3},{val:4}]; a.map((b)=>{b.val**2}); JSON.stringify(a);
Ken Redler 2017-10-19

66

두 가지 방법 사이의 주요 차이점은 개념 및 문체입니다 : 당신이 사용하는 forEach당신이 뭔가를 할 때 배열의 각 요소 ( "와"하고는 "부작용"을 의미 인용 포스트, 내가 무슨 생각입니다) , 반면 배열의 각 요소 map복사하고 변환 하려는 경우 (원본을 변경하지 않고) 사용합니다.

둘 다 mapforEach배열의 각 항목에 대해 함수를 호출하고 해당 함수가 사용자 정의되어 있기 때문에 하나를 사용하여 수행 할 수있는 작업이 거의 없습니다. 추악하지만 map배열을 제자리에서 수정하거나 배열 요소로 무언가를 수행하는 데 사용할 수 있습니다.

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.map(function(el) {
    el.val++; // modify element in-place
    alert(el.val); // do something with each element
});
// a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]

그러나 사용하려는 의도는 훨씬 명확하고 명확합니다 forEach.

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.forEach(function(el) { 
    el.val++;
    alert(el.val);
});

특히 현실 세계에서 일반적으로 el그렇듯이 사람이 읽을 수있는 유용한 변수 인 경우 :

cats.forEach(function(cat) { 
    cat.meow(); // nicer than cats[x].meow()
});

같은 방식 forEach으로 새 배열을 만드는 데 쉽게 사용할 수 있습니다 .

var a = [1,2,3],
    b = [];
a.forEach(function(el) { 
    b.push(el+1); 
});
// b is now [2,3,4], a is unchanged

그러나 사용하는 것이 더 깨끗합니다 map.

var a = [1,2,3],
    b = a.map(function(el) { 
        return el+1; 
    });

또한 map새 어레이를 만들기 때문에 필요한 모든 것이 반복 일 때, 특히 대형 어레이의 경우 적어도 약간의 성능 / 메모리 적중이 발생할 수 있습니다. http://jsperf.com/map-foreach를 참조하십시오.

이러한 함수를 사용하려는 이유는 자바 스크립트에서 배열 조작을해야 할 때마다 유용합니다. (브라우저 환경에서 자바 스크립트에 대해 이야기하고 있더라도) 거의 항상 코드에 직접 적지 않은 배열에 액세스하고 있습니다. 페이지의 DOM 요소 배열, AJAX 요청에서 가져온 데이터 또는 사용자가 양식에 입력 한 데이터를 처리 할 수 ​​있습니다. 한 가지 일반적인 예는 외부 API에서 데이터를 가져 오는 것입니다. 여기서 map데이터를 원하는 형식으로 변환하고 forEach사용자에게 표시하기 위해 새 배열을 반복 하는 데 사용할 수 있습니다.


나는 사람들이 .map()항상 인라인 요소를 수정하는 데 사용 하는 것을 봅니다 . 내가 사용하는 주요 장점이었다 인상이었다 .map이상.forEach
chovy을

1
@chovy 결과의 배열을 만들 것인지 여부에 따라 선택해야한다고 생각합니다. .map요소를 수정할 수 있지만 필요하지 않은 배열을 생성합니다. 하나를 선택하거나 다른 당신이 부작용이 있는지 여부 독자의 추측을 할 수 있습니다 방법 또한 고려해야합니다
leewz

16

(Ken Redler의) 투표 된 답변은 잘못된 것입니다.

컴퓨터 과학 의 부작용 은 함수 / 메소드의 속성이 글로벌 상태를 변경한다는 것을 의미합니다 [wiki] . 좁은 의미에서 여기에는 인수가 아닌 전역 상태에서 읽는 것도 포함될 수 있습니다. 명령형 또는 OO 프로그래밍에서는 대부분의 경우 부작용이 나타납니다. 그리고 당신은 아마 깨닫지 못하고 그것을 사용하고있을 것입니다.

significiant 간의 차이 forEachmap그 인 map동안, 할당 된 메모리에 저장한다 반환 값 forEach멀리 던진다. 자세한 내용은 emca 사양 을 참조하십시오.

사람들 forEach이 부작용을 원할 때 사용 한다고 말하는 이유 는의 반환 값 forEach이 항상이라는 것 undefined입니다. 부작용이없는 경우 (전역 상태를 변경하지 않음) 함수는 CPU 시간을 낭비하는 것입니다. 최적화 컴파일러는이 코드 블록을 제거하고 최종 값 ( undefined)으로 대체합니다 .

참고로 JavaScript는 부작용에 대한 제한이 없습니다. 내부에서 원래 배열을 계속 수정할 수 있습니다 map.

var a = [1,2,3]; //original
var b = a.map( function(x,i){a[i] = 2*x; return x+1} );
console.log("modified=%j\nnew array=%j",a,b);
// output:
// modified=[2,4,6]
// new array=[2,3,4]

2
이 질문과 그에 대한 답변과 댓글은 2 년마다 돌아 다니는 재미가 있습니다. 메모리 할당 측면에서 JS에서 맵이 구현되는 방식은 또 다른 좋은 각도입니다.
Ken Redler

7

이것은 예상치 못한 대답을 가진 아름다운 질문입니다.

다음은의 공식 설명을Array.prototype.map() 기반으로합니다 .

없다 아무것도forEach() 가 할 수있는 map()캔을하지 않음. 즉, map()A는 엄격한 슈퍼 세트forEach().

map()일반적으로 새 배열을 만드는 데 사용 되지만 현재 배열을 변경 하는데도 사용할 수 있습니다. 다음 예는이를 설명합니다.

var a = [0, 1, 2, 3, 4], mapped = null;
mapped = a.map(function (x) { a[x] = x*x*x; return x*x; });
console.log(mapped); // logs [0, 1, 4, 9, 16]  As expected, these are squares.
console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!

위의 예에서, a편리하게되도록 설정 a[i] === ii < a.length. 그럼에도 불구하고의 힘 map(), 특히 호출되는 배열을 변경하는 기능을 보여줍니다 .

참고 1 :
공식 설명 은 호출되는 배열의 길이를map() 변경할 수도 있음을 의미합니다 ! 그러나 나는 이것을 할 (좋은) 이유를 알 수 없습니다.

주 2 :
동안 map()지도의 수퍼 세트이고 forEach(), forEach()하나의 변화를 소정의 배열을 계속하고자 표기가. 이것은 당신의 의도를 명확하게합니다.

이것이 도움이 되었기를 바랍니다.


8
실제로 forEach가 할 수있는 것은 맵이 할 수없는 일이 있습니다. 배열을 반환하지 않습니다.
Antti Haapala 2014-07-29

1
매핑 함수에 세 번째 인수를 사용하여 범위 변수 대신 대상 배열을 변경할 수도 있습니다.mapped = a.map(function (x, i, arr) { arr[i] = x * x * x; return x * x; });.
pdoherty926

@ pdoherty926 사실 할 수 있지만 a.forEach(function(x, i, arr) { ..., 다시, 당신은 할 의도가있는 경우 개념적으로 더 올바른 방법입니다, 돌연변이 반대로 각 원본 항목을 지도 또 다른 하나 개의 배열에서 값을
코니

@conny : 동의합니다. 또한 유사한 질문에 대한 이 답변을 참조하십시오 .
Sumukh Barve

3

당신은 사용할 수 map는 것처럼 forEach.

하지만해야 할 일보다 더 많은 일을 할 것입니다.

scope임의의 객체가 될 수 있습니다. 반드시 그런 것은 아닙니다 this.

mapforEach에 대한 실제 용도가 있는지 여부 와 for for또는 while루프 가 실제로 사용되는지 묻습니다 .


그러나 여기서 "scope"와 "this"가 모두 호출되는 이유 : func.call (scope, this [i], i, this); 범위가 현재 개체 인 "this"와 같은 매개 변수가 아닙니까?
JohnMerlino 2010-06-14

아니요, 현재 개체와 같을 있습니다. 객체 자체는 세 번째 매개 변수로 배열에 전달됩니다. scope = scope || this"만약 scope거짓 (정의되지 않음, null, 거짓 등) 인 경우 범위를 this대신 설정 하고 계속합니다"를 의미합니다.
wombleton

이것과 같지 않은 예를 연결해 주시겠습니까?
JohnMerlino 2010-06-15

developer.mozilla.org/en/Core_JavaScript_1.5_Reference/...는 "객체 메소드로 배열의 내용을 인쇄"미만 보유
wombleton

1

이전의 모든 질문이 맞지만 분명히 다른 구분을 할 것입니다. map및 의 사용은 forEach의도를 암시 할 수 있습니다.

나는 map단순히 어떤 방식 으로든 기존 데이터를 변환 할 때 사용 하고 싶습니다 (하지만 원래 데이터가 변경되지 않았는지 확인하고 싶습니다.

forEach컬렉션을 수정할 때 사용하고 싶습니다 .

예를 들어

var b = [{ val: 1 }, { val: 2 }, { val: 3 }];
var c = b.map(function(el) {
    return { val: el.val + 1 }; // modify element in-place
});
console.log(b);
//  [{ val: 1 }, { val: 2 }, { val: 3 }]
console.log(c);
//  [{ val: 3 }, { val: 4 }, { val: 5 }]

내 경험 법칙 map은 항상 소스 목록의 각 요소에 대해 반환 할 새 개체 / 값을 만들고 각 요소 에 대해 일부 작업을 수행하는 대신 반환 할 때 확인하는 것입니다.

기존 목록을 실제로 수정할 필요가없는 한 제자리에서 수정하는 것은 의미가 없으며 기능 / 불변 프로그래밍 스타일에 더 적합합니다.


1

TL, DR 답변-

map은 항상 다른 배열을 반환합니다.

forEach는 그렇지 않습니다. 그것이 무엇을하는지 결정하는 것은 당신에게 달려 있습니다. 원하는 경우 배열을 반환하고 원하지 않는 경우 다른 작업을 수행합니다.

특정 상황에서는 유연성이 바람직합니다. 당신이 다루는 것이 아니라면 map을 사용하십시오.


0

다시 한 번, 저는 5 년 전 질문에 대한 답변을 추가하는 네크로맨서 같은 느낌이 듭니다 (행복하게도 최근 활동이 있기 때문에 죽은 사람을 방해하는 유일한 사람이 아닙니다 :).

다른 사람들은 기능 간의 차이점에 대한 주요 질문에 대해 이미 게시했습니다. 이 아니라면...

다음과 같이 숫자를 조작하는 것 외에 자바 스크립트에서 이러한 메서드를 실제로 사용하는 것이 있습니까 (데이터베이스를 업데이트하지 않기 때문에) :

... 당신이 물어 보면 재밌 네요. 오늘 바로 변환을 위해 맵을 사용하여 정규식의 여러 값을 여러 변수에 할당하는 코드를 작성했습니다. 매우 복잡한 텍스트 기반 구조를 시각화 가능한 데이터로 변환하는 데 사용되었습니다 ...하지만 단순성을 위해 날짜 문자열을 사용하는 예제를 제공 할 것입니다. , map 대신에 Date-object를 사용했을 것입니다. 그 자체로 훌륭하게 작업을 수행했을 것입니다).

const DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/;
const TEST_STRING = '2016-01-04T03:20:00.000Z';

var [
    iYear,
    iMonth,
    iDay,
    iHour,
    iMinute,
    iSecond,
    iMillisecond
    ] = DATE_REGEXP
        // We take our regular expression and...
        .exec(TEST_STRING)
        // ...execute it against our string (resulting in an array of matches)...
        .slice(1)
        // ...drop the 0th element from those (which is the "full string match")...
        .map(value => parseInt(value, 10));
        // ...and map the rest of the values to integers...

// ...which we now have as individual variables at our perusal
console.debug('RESULT =>', iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond);

그래서 ... 이는 단지 예일뿐입니다. 데이터에 대해 매우 기본적인 변환 만 수행했습니다 (예를 들어).지도없이이 작업을 수행하는 것은 훨씬 더 지루한 작업이었을 것입니다.

물론, 아직 많은 브라우저 (적어도 완전히) 지원한다고 생각하지 않는 JavaScript 버전으로 작성 되었지만-우리는 거기에 도달하고 있습니다. 브라우저에서 실행해야한다면 잘 변환 될 것이라고 믿습니다.

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