어떻게 break문이 없을 수 있는가 궁금하기도 했지만 (나도 잘 모르지만)
자바스크립트를 예로 들어보자.
[1,2,3,4,5].forEach(function(v) {
if (v==2) console.log(v)
});
배열의 값이 2인 경우만 출력하도록 한 것으로 이렇게 배열중 일부값을 찾아서 뭔가를 수행하고자 하는 것이다. 위 예제는 잘 동작하지만 사실 이 예제는 2를 출력한 후에도 불필요하게 3,4,5도 순회하게 되기 때문에 여기서 성능을 위해서 break문으로 불필요한 순회를 없애고 싶어진다.
var Break = new Error('Break');
try {
[1,2,3,4,5].forEach(function(v) {
if (v==2) {
console.log('v: ', v)
throw Break;
}
});
} catch (e) {
if (e!= Break) throw Break;
}
자바스크립트의 경우 break문이 없기 때문에 위처럼 Break라는 커스톰 오류객체를 정의해서 순회하다가 멈춰하 하는 곳에서 예외를 던져서 순회를 멈출 수 있다. 이는 try-catch를 교묘히 이용해서 원하는 동작을 하도록 한 것이지만 코드에서 보듯이 원하는 것에 비해서 코드가 너무 지저분해져서 가독성도 그다지 좋지 않다.
여기서 forEach에 break 조합대신 사용할 수 있는 것이 some()이다. some은 컬렉션의 요소 중 최소 1개라도 조건을 만족시키는지 검사하는 메서드이고 언어에 따라 some이 아닌 경우도 있지만 비슷한 기능을 하는 언어는 존재한다.(스칼라의 경우에는 exists이다.) 위에서 작성한 예제와 똑같은 함수를 some()를 사용해서 다음과 같이 작성할 수 있다.
[1,2,3,4,5].some(function(v) {
if(v == 2) console.log(v);
return (v ==2);
});
some()은 조건이 true가 되는 순간 순회를 멈추기 때문에 우리가 원하는 동작을 충족시킬 수 있다. 억지로 break문을 사용하는 것보다는 훨씬 소스도 깔끔해 졌고 함수의 용도에도 맞아보인다.
forEach 함수의 경우 모든 함수를 순회사면서 무엇인가를 하기 위해서 사용되지만, some 함수의 경우는 predicate 함수를 받아서 해당 함수를 만족하는 값이 컬렉션 안쪽에 존재하는지를 확인하는데 사용하는데 사용됩니다.
some 함수를 불필요한 컬렉션의 순회를 회피할 수는 있겠지만 some메서드의 원래 목적과는 다릅니다.
마찬가지로 forEach 대신에 map 함수를 사용할 수도 있지만 따로 forEach메서드가 존재하는 이유도 이와 같습니다.
ex:) [1,2,3,4].map(function(){ // do somethong })
map => 컬렉션의 원소를 다른 원소로 맵핑
some => 컬렉션 안에 predicate를 만족하는 원소가 하나라도 있는가
예.. 말씀하신대로 some함수의 용도가 글에 쓴 용도는 아니고 원소의 포함여부를 찾는 메서드입니다. 여기서는 이 목적의 some함수의 특성을 이용한 것을 설명한 것이고 커스텀 오류객체를 만들어서 예외를 던지를 것도 원래 의도와는 좀 다르므로 어차피 그럴바엔 some함수를 사용하는 것도 한가지 방법이 될 수 있다는 얘기를 하려고 한 것입니다.
헉... 10월6일 글을 이제 보다니;;; -_ㅠ...
잘 읽고 갑니다 ㅎㅎ 항상 좋은 글 감사합니다 ㅎ
^^ 예 잘 읽어주셨다니 감사합니다. ㅎ
대박자료네요
return true; 가 break; 라면, return false; 는 continue; 와 같더군요. 테스트해보니 잘 동작합니다. some 을 결과값으로 판단할때만 사용했는데, forEach 대용으로 사용하는게 가능합니다. 느낌은 gvim에서 reverse search 를 하는 듯한...^^
some 내부에서 break 와 continue, 그리고 할당하는 것들은 문제가 없지만, some 밖에서 return 값을 어떻게 판단할지가 약간 혼동됩니다. true가 중단인지, false가 중단인지...ㅠㅠ
제 생각은 some 바깥에 주석을 달아서 구분해야 할 것으로 보입니다만...여튼 좋은 팁 감사합니다...^^
return true/false 를 그렇게 쓰는건 생각못해봤네요. 작성할 때 편하긴 한데 코드를 읽을 때 헷갈릴 요소가 있다는 부분은 동의합니다.
forEach 에서 return true; 는 break 의 대안이 될 수 없습니다.
다음 예제를 실행해보면 기대와 다른 결과 나오는 것 확인할 수 있을겁니다.
var fruits = [
{ name: "apple", price : 250 },
{ name: "banana", price : 430 },
{ name: "orange", price : 320 }
];
var fruit_names = [];
fruits.forEach(function (fruit) {
if(fruit.price > 400)
return true;
fruit_names.push(fruit.name);
});
console.log(fruit_names);
apple 만 기대하겠지만 결과는 apple, orange 가 나올겁니다.