etc./StackOverFlow

break 호출과 같은 Array.forEach 단락

청렴결백한 만능 재주꾼 2021. 12. 21. 22:08
반응형

질문자 :Scott Klarenbach


[1,2,3].forEach(function(el) { if(el === 1) break; });

JavaScript에서 forEach 메서드를 사용하여 이 작업을 수행하려면 어떻게 해야 합니까? return; 시도했다; , return false; 그리고 break . break 가 충돌하고 return 은 반복을 계속하는 것 외에는 아무것도 하지 않습니다.



forEach break 하는 기본 제공 기능은 없습니다. 실행을 중단하려면 일종의 예외를 throw해야 합니다. 예를 들어

 var BreakException = {}; try { [1, 2, 3].forEach(function(el) { console.log(el); if (el === 2) throw BreakException; }); } catch (e) { if (e !== BreakException) throw e; }

JavaScript 예외는 그다지 아름답지 않습니다. 내부 break 해야 하는 경우 전통적인 for 루프가 더 적절할 수 있습니다.

Array#some 사용 #some

대신 Array#some .

 [1, 2, 3].some(function(el) { console.log(el); return el === 2; });

이 작품 때문에 some 반환 true 배열 순서대로 실행되는 즉시 콜백의 등은 반환 true 단락 나머지의 실행을.

some , 그 역 every ( return false 중지됨) 및 forEach 는 모두 ECMAScript Fifth Edition 메서드로, 누락된 브라우저 Array.prototype


bobince

이제 새로운 for 루프를 사용하여 ECMAScript2015(일명 ES6)에서 이를 수행하는 훨씬 더 나은 방법이 있습니다. 예를 들어, 이 코드는 숫자 5 뒤에 배열 요소를 인쇄하지 않습니다.

 let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let el of arr) { console.log(el); if (el === 5) { break; } }

문서에서:

for...infor...of 문은 모두 무언가를 반복합니다. 그들 사이의 주요 차이점은 무엇을 반복하는지에 있습니다. for...in 문은 원래 삽입 순서대로 개체의 열거 가능한 속성을 반복합니다. for...of 문은 iterable 객체가 반복하도록 정의한 데이터를 반복합니다.

반복에 인덱스가 필요하십니까? Array.entries() 사용할 수 있습니다.

 for (const [index, el] of arr.entries()) { if ( index === 5 ) break; }

canac

모든 방법을 사용할 수 있습니다.

 [1,2,3].every(function(el) { return !(el === 1); });

ES6

 [1,2,3].every( el => el !== 1 )

이전 브라우저 지원 사용:

 if (!Array.prototype.every) { Array.prototype.every = function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this && !fun.call(thisp, this[i], i, this)) return false; } return true; }; }

자세한 내용은 여기 .


Valdemar_Rudolfovich

Array.prototype.forEach() 의 MDN 문서 에서 인용:

예외를 throw하는 것 외에는 forEach() 루프를 중지하거나 중단 할 수 있는 방법이 없습니다. 이러한 동작이 필요한 경우 .forEach() 메서드가 잘못된 도구 이므로 대신 일반 루프를 사용하세요. 술어에 대한 배열 요소를 테스트하고 부울 반환 값이 필요한 경우 대신 every() 또는 some()

@bobince가 제안한 대로 귀하의 코드(질문에서)의 경우 Array.prototype.some() 사용하십시오. 그것은 당신의 사용 사례에 아주 잘 맞습니다.

Array.prototype.some() Boolean 변환할 때 true가 되는 값)을 반환하는 값을 찾을 때까지 배열에 있는 각 요소에 대해 콜백 함수를 한 번 실행합니다. 그러한 요소가 발견되면 some() 즉시 true를 반환합니다. 그렇지 않으면 some() 은 false를 반환합니다. 콜백은 값이 할당된 배열의 인덱스에 대해서만 호출됩니다. 삭제되었거나 값이 할당된 적이 없는 인덱스에 대해서는 호출되지 않습니다.


Rahul Desai

forEach 사용하지 않는 것이 훨씬 나을 것입니다. 대신 일반 for 루프를 사용하면 예상대로 정확하게 작동합니다.

 var array = [1, 2, 3]; for (var i = 0; i < array.length; i++) { if (array[i] === 1){ break; } }

Weston Ganger

코드 예제에서 Array.prototype.find 가 찾고 있는 것처럼 보입니다: Array.prototype.find()Array.prototype.findIndex()

 [1, 2, 3].find(function(el) { return el === 2; }); // returns 2

Oliver Moran

콜백 함수 내에서 false를 반환할 수 jqueryeach 메소드를 사용하는 것을 고려하십시오.

 $.each(function(e, i) { if (i % 2) return false; console.log(e) })

Lodash 라이브러리는 map/reduce/fold 등으로 연결할 수 있는 takeWhile

 var users = [ { 'user': 'barney', 'active': false }, { 'user': 'fred', 'active': false }, { 'user': 'pebbles', 'active': true } ]; _.takeWhile(users, function(o) { return !o.active; }); // => objects for ['barney', 'fred'] // The `_.matches` iteratee shorthand. _.takeWhile(users, { 'user': 'barney', 'active': false }); // => objects for ['barney'] // The `_.matchesProperty` iteratee shorthand. _.takeWhile(users, ['active', false]); // => objects for ['barney', 'fred'] // The `_.property` iteratee shorthand. _.takeWhile(users, 'active'); // => []

vittore

Dean Edward의 제안 을 사용하고 StopIteration 오류를 발생시켜 오류를 포착하지 않고도 루프를 벗어나고 싶다면 다음 함수를 사용할 수 있습니다( 원래 here ):

 // Use a closure to prevent the global namespace from be polluted. (function() { // Define StopIteration as part of the global scope if it // isn't already defined. if(typeof StopIteration == "undefined") { StopIteration = new Error("StopIteration"); } // The original version of Array.prototype.forEach. var oldForEach = Array.prototype.forEach; // If forEach actually exists, define forEach so you can // break out of it by throwing StopIteration. Allow // other errors will be thrown as normal. if(oldForEach) { Array.prototype.forEach = function() { try { oldForEach.apply(this, [].slice.call(arguments, 0)); } catch(e) { if(e !== StopIteration) { throw e; } } }; } })();

위의 코드는 자체 try-catch 절을 수행하지 않고도 다음과 같은 코드를 실행할 수 있는 기능을 제공합니다.

 // Show the contents until you get to "2". [0,1,2,3,4].forEach(function(val) { if(val == 2) throw StopIteration; alert(val); });

기억해야 할 한 가지 중요한 점은 이것이 이미 존재하는 경우에만 Array.prototype.forEach 함수를 업데이트한다는 것입니다. 이미 존재하지 않는 경우 수정하지 않습니다.


Chris West

짧은 대답: for...break forEach 깨지지 않도록 코드를 변경하십시오. .some() 또는 .every() 를 사용 for...break 를 에뮬레이트하지 마십시오. for...break 루프를 피하기 위해 코드를 다시 작성 for...break . 이 방법을 사용할 때마다 for...break 대안 신이 새끼 고양이를 죽입니다.

긴 대답:

.some().every() 을 모두 반환 boolean 값은 .some() 반환 true 에 대한 요소가 함수가 반환이 통과하면 true 모든 반환, false 에 대한 요소가 함수가 반환이 전달 된 경우 false . 이것이 그 기능이 의미하는 바입니다. 의미가 없는 기능을 사용하는 것은 CSS 대신 레이아웃에 테이블을 사용하는 것보다 훨씬 나쁩니다. 왜냐하면 코드를 읽는 모든 사람을 짜증나게 하기 때문입니다.

for...break 대안으로 사용할 수 있는 유일한 방법은 부작용을 만드는 것입니다( .some() for...break 와 크게 다르지 않습니다.

따라서 .some() 또는 .every()for...break 루프 대안으로 사용하는 것은 부작용이 없습니다. 이것은 for...break 보다 훨씬 깨끗하지 않습니다. 이것은 실망스럽기 때문에 그렇지 않습니다. 더 나은.

for...break 가 필요하지 않도록 항상 코드를 다시 작성할 수 있습니다. 다음을 사용하여 배열을 필터링 할 수 있습니다 .filter() , 사용 배열을 분할 할 수 있습니다 .slice() 등등, 다음 사용 .forEach() 또는 .map() 배열의 부분.


Max

이것은 내가 문제를 해결하기 위해 생각해 낸 것입니다 ... 원래 질문자가 가지고 있던 문제를 해결한다고 확신합니다.

 Array.prototype.each = function(callback){ if(!callback) return false; for(var i=0; i<this.length; i++){ if(callback(this[i], i) == false) break; } };

그런 다음 다음을 사용하여 호출합니다.

 var myarray = [1,2,3]; myarray.each(function(item, index){ // do something with the item // if(item != somecondition) return false; });

콜백 함수 내에서 false를 반환하면 중단이 발생합니다. 실제로 작동하지 않는 경우 알려주십시오.


tennisgent

이전에 언급했듯이 .forEach() 중단할 수 없습니다.

다음은 ES6 Iterator로 foreach를 수행하는 약간 더 현대적인 방법입니다. 반복할 때 index / value 직접 액세스할 수 있습니다.

 const array = ['one', 'two', 'three']; for (const [index, val] of array.entries()) { console.log('item:', { index, val }); if (index === 1) { console.log('break!'); break; } }

산출:

 item: { index: 0, val: 'one' } item: { index: 1, val: 'two' } break!

연결


Alex

내가 생각해낸 또 다른 개념:

 function forEach(array, cb) { var shouldBreak; function _break() { shouldBreak = true; } for (var i = 0, bound = array.length; i < bound; ++i) { if (shouldBreak) { break; } cb(array[i], i, array, _break); } } // Usage forEach(['a','b','c','d','e','f'], function (char, i, array, _break) { console.log(i, char); if (i === 2) { _break(); } });


c24w

반복 후에 배열에 액세스할 필요가 없으면 배열의 길이를 0으로 설정하여 구제할 수 있습니다. 반복 후에도 여전히 필요한 경우 슬라이스를 사용하여 복제할 수 있습니다.

 [1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) { if (index === 3) arr.length = 0; });

또는 클론 사용:

 var x = [1,3,4,5,6,7,8,244,3,5,2]; x.slice().forEach(function (item, index, arr) { if (index === 3) arr.length = 0; });

코드에서 임의의 오류를 던지는 것이 훨씬 더 나은 솔루션입니다.


3rdEden

다른 사이트에서 이 솔루션을 찾았습니다. try/catch 시나리오에서 forEach를 래핑할 수 있습니다.

 if(typeof StopIteration == "undefined") { StopIteration = new Error("StopIteration"); } try { [1,2,3].forEach(function(el){ alert(el); if(el === 1) throw StopIteration; }); } catch(error) { if(error != StopIteration) throw error; }

자세한 내용은 여기: http://dean.edwards.name/weblog/2006/07/enum/


RussellUresti

이것은 for 루프이지만 forEach()와 마찬가지로 루프에서 객체 참조를 유지하지만 중단할 수 있습니다.

 var arr = [1,2,3]; for (var i = 0, el; el = arr[i]; i++) { if(el === 1) break; }

jamos

또 다른 접근법

 var wageType = types.filter(function(element){ if(e.params.data.text == element.name){ return element; } }); console.dir(wageType);

Harry Bosh

나는 그 목적을 위해 nullhack 을 사용하는데, 그것은 오류 null 속성에 접근을 시도합니다:

 try { [1,2,3,4,5] .forEach( function ( val, idx, arr ) { if ( val == 3 ) null.NULLBREAK; } ); } catch (e) { // e <=> TypeError: null has no properties } //

public override

forEach 구문을 유지하려면 이것이 효율적으로 유지하는 방법입니다(일반 for 루프만큼 좋지는 않지만). 루프에서 벗어나고 싶은지 여부를 알고 있는 변수를 즉시 확인하십시오.

이 예제에서는 완료 정보를 저장하는 데 필요한 forEach 주변에 함수 범위 를 만들기 위해 익명 함수를 사용합니다.

 (function(){ var element = document.getElementById('printed-result'); var done = false; [1,2,3,4].forEach(function(item){ if(done){ return; } var text = document.createTextNode(item); element.appendChild(text); if (item === 2){ done = true; return; } }); })();
 <div id="printed-result"></div>

내 2센트.


Justus Romijn

루프를 끊는 유틸리티를 제공 array.prototype.every 함수를 사용하십시오. Mozilla 개발자 네트워크에 대한 Javascript 문서의 예는 여기를 참조하십시오.


Yiling

@bobince에 동의하고 찬성합니다.

또한 참고로:

Prototype.js에는 다음과 같은 목적이 있습니다.

 <script type="text/javascript"> $$('a').each(function(el, idx) { if ( /* break condition */ ) throw $break; // do something }); </script>

$break 는 내부적으로 Prototype.js에 의해 포착 및 처리되어 "각각" 주기를 중단하지만 외부 오류는 생성하지 않습니다.

자세한 내용은 Prototype.JS API 를 참조하세요.

jQuery도 방법이 있습니다. 핸들러에서 false를 반환하여 루프를 조기에 중단하면 됩니다.

 <script type="text/javascript"> jQuery('a').each( function(idx) { if ( /* break condition */ ) return false; // do something }); </script>

자세한 내용은 jQuery API 를 참조하세요.


Dmitri Sologoubenko

이것은 여전히 모든 요소를 순환하기 때문에 가장 효율적이지는 않지만 매우 간단한 것을 고려할 가치가 있다고 생각했습니다.

 let keepGoing = true; things.forEach( (thing) => { if (noMore) keepGoing = false; if (keepGoing) { // do things with thing } });

martyman

당신은 나를 위해 작동하는 아래의 코드를 따를 수 있습니다:

 var loopStop = false; YOUR_ARRAY.forEach(function loop(){ if(loopStop){ return; } if(condition){ loopStop = true; } });

BERGUIGA Mohamed Amine

나는 그것이 옳지 않다는 것을 알고 있습니다. 루프를 깨는 것이 아닙니다. 쥬갓이다

 let result = true; [1, 2, 3].forEach(function(el) { if(result){ console.log(el); if (el === 2){ result = false; } } });


Durgpal Singh

귀하의 경우와 같이 이미 배열에 있는 요소의 값을 기반으로 중단해야 하는 경우(즉, 중단 조건이 배열에 요소 값이 할당된 후 변경될 수 있는 런타임 변수에 의존하지 않는 경우) 조합을 사용할 수도 있습니다 다음과 같이 slice()indexOf().

forEach가 'Apple'에 도달했을 때 중단해야 하는 경우 사용할 수 있습니다.

 var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]; var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple")); // fruitsToLoop = Banana,Orange,Lemon fruitsToLoop.forEach(function(el) { // no need to break });

W3Schools.com에 명시된 대로 slice() 메서드는 배열에서 선택한 요소를 새 배열 객체로 반환합니다. 원래 배열은 변경되지 않습니다.

JSFiddle 에서 보기

누군가를 돕기를 바랍니다.


Ula

"찾기"로 시도:

 var myCategories = [ {category: "start", name: "Start", color: "#AC193D"}, {category: "action", name: "Action", color: "#8C0095"}, {category: "exit", name: "Exit", color: "#008A00"} ]; function findCategory(category) { return myCategories.find(function(element) { return element.category === category; }); } console.log(findCategory("start")); // output: { category: "start", name: "Start", color: "#AC193D" }

GigolNet Guigolachvili

Promise에서 함수를 래핑해 보지 않겠습니까?

내가 그것을 제기하는 유일한 이유는 forEach와 유사한 방식으로 작동하는 API의 함수를 사용하고 있기 때문입니다. 값을 찾으면 계속 반복되는 것을 원하지 않고 무언가를 반환해야 하므로 간단히 Promise를 해결하고 그렇게 할 것입니다.

 traverseTree(doc): Promise<any> { return new Promise<any>((resolve, reject) => { this.gridOptions.api.forEachNode((node, index) => { //the above function is the one I want to short circuit. if(node.data.id === doc.id) { return resolve(node); } }); }); }

그런 다음 다음과 같은 결과로 작업을 수행하기만 하면 됩니다.

 this.traverseTree(doc).then((result) => { this.doSomething(result); });

위의 예는 typescript에 있습니다. 단순히 유형을 무시하십시오. 논리는 루프에서 "탈출"하는 데 도움이 되기를 바랍니다.


Willie

어레이 길이를 줄여 간단한 어레이 접합은 어떻습니까 ???

현재 배열이 엉망이 되므로 구조 해제 기능을 사용하여 복사본을 만들어야 합니다...

예:

 const arr = [1, 2, 3, 4, 5]; // Don't forget to work with a copy of the original array otherwise you will loose your data contained inside [...arr].forEach(function(value, index, copiedArrInstance) { if (index === 2) copiedArrInstance.length = 0; console.log(value); }); // you will still have your array intact console.log(arr);


ntdash

break , continue , returnasync / await 까지 허용 forEach 변형을 만들 수 있습니다. (TypeScript로 작성된 예제)

 export type LoopControlOp = "break" | "continue" | ["return", any]; export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp; Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) { for (let i = 0; i < this.length; i++) { const controlOp = func(this[i], i, this); if (controlOp == "break") break; if (controlOp == "continue") continue; if (controlOp instanceof Array) return controlOp[1]; } }; // this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) { for (let i = 0; i < this.length; i++) { const controlOp = await func(this[i], i, this); if (controlOp == "break") break; if (controlOp == "continue") continue; if (controlOp instanceof Array) return controlOp[1]; } };

용법:

 function GetCoffee() { const cancelReason = peopleOnStreet.ForEach((person, index)=> { if (index == 0) return "continue"; if (person.type == "friend") return "break"; if (person.type == "boss") return ["return", "nevermind"]; }); if (cancelReason) console.log("Coffee canceled because: " + cancelReason); }

Venryx

const Book = {"Titles":[ {"Book3" : "BULLETIN 3"}, {"Book1" : "BULLETIN 1"}, {"Book2" : "BULLETIN 2"} ]} const findbystr = function(str) { Book.Titles.forEach(function(data) { if (typeof data[str] != 'undefined') { return data[str]; } }, str) } book = findbystr('Book1'); console.log(book);

Samuel Gray

출처 : http:www.stackoverflow.com/questions/2641347/short-circuit-array-foreach-like-calling-break

반응형