메뉴관리를 구현하면서 forEach를 통해 하위 메뉴를 찾는 로직을 수행하려고 하였는데 원하는 결과값이 나오지 않는 문제가 발생하였습니다. 아래의 글은 이 문제를 해결하는 방법에 대한 정리 합니다.
아래와 같은 메뉴가 있을 때 [시스템] 메뉴를 수정하는 경우 상위 메뉴 선택 시 [시스템]의 하위 메뉴는 제외하는 로직을 추가하려고 메뉴 항목을 forEach 하여 [시스템] 메뉴의 하위 항목을 검색하여 상위 메뉴 선택에서 제외하는 로직을 구현하려고 하였습니다. 원하는 결과는 [시스템] 메뉴의 4개 항목만 제외되어야 하는데 [환경설정]의 하위 메뉴까지 제외되는 문제가 발생하였습니다.
인터넷을 조회한 결과 javascript 나 Node.js에서 배열에 대한 forEach를 사용하여 값을 처리하는 경우 break가 오작동된다고 합니다. 그리고 break의 처리를 위해서는 some을 사용하여 구현이 가능합니다.
그냥 for문을 사용하여 처리가 가능한데 보다 깔끔한 코드는 forEach, some이 더 표현이 좋습니다.
forEach 함수와 some함수
아래와 같은 컬렉션 배열이 있고 원하는 구현 로직은 값(value)이 40 미만의 값을 추출하고 40 이상일 경우에는 break문을 수행하고 싶습니다. (1차원으로 처리된 트리구조를 생성한 뒤 특정 트리의 하위 항목을 찾는 로직을 구현하려고 했는데 오작동이 발생하여 forEach에 대한 오작동을 발견하였습니다.)
const collection = [
{name: "Name #1", value: 10},
{name: "Name #2", value: 20},
{name: "Name #3", value: 30},
{name: "Name #4", value: 40},
{name: "Name #5", value: 50},
{name: "Name #6", value: 40},
{name: "Name #7", value: 30},
{name: "Name #8", value: 20},
{name: "Name #9", value: 10},
];
forEach 함수
forEach를 사용하여 아래와 같이 구현해 보았습니다. return false;로 함수를 벗어나는 로직을 구현하려고 하였는데(jQuery의 each는 return false;가 break 기능을 수행합니다.) 원하는 결과가 아니었습니다. 배열 요소에서 40 미만의 모든 값을 추출하였습니다.
let ret1 = [];
collection.forEach((item) => {
if(item.value < 40) ret1.push(item);
if(item.value >= 40) {
return false;
}
});
console.log("forEach Result : " + JSON.stringify(ret1));
forEach Result : [
{"name":"Name #1","value":10},
{"name":"Name #2","value":20},
{"name":"Name #3","value":30},
{"name":"Name #7","value":30},
{"name":"Name #8","value":20},
{"name":"Name #9","value":10}
]
some 함수
컬렉션에서 break를 수행하기 위해서는 some함수를 사용하여 아래와 같이 처리가 가능합니다.
let ret2 = [];
collection.some((item) => {
if(item.value < 40) ret2.push(item);
if(item.value >= 40) {
return true;
}
});
console.log("some Result : " + JSON.stringify(ret2));
some Result : [
{"name":"Name #1","value":10},
{"name":"Name #2","value":20},
{"name":"Name #3","value":30}
]
메뉴의 하위 항목 찾는 예시
다음은 특정 메뉴를 검색한 후에 하위 메뉴를 검색하는 로직을 비교한 코드입니다. 원하는 로직은 2번 메뉴를 찾고 그 하위 메뉴를 반환하도록 구현하려 합니다. 아래의 코드처럼 2번 메뉴를 찾고 그 하위 메뉴를 검색하도록 구현한 로직인데 forEach의 경우에는 3번대의 메뉴까지 출력합니다. some의 return true를 사용하여 break를 수행합니다. return false는 continue 역할을 수행합니다.
const menutable = [
{key: "1", name: "Menu #1", depth: 0},
{key: "1-1", name: "Menu #1-1", depth: 1},
{key: "1-1-1", name: "Menu #1-1-1", depth: 2},
{key: "1-2", name: "Menu #1-2", depth: 1},
{key: "1-3", name: "Menu #1-3", depth: 1},
{key: "2", name: "Menu #2", depth: 0},
{key: "2-1", name: "Menu #2-1", depth: 1},
{key: "2-1-1", name: "Menu #2-1-1", depth: 2},
{key: "2-1-2", name: "Menu #2-1-2", depth: 2},
{key: "2-2", name: "Menu #2-2", depth: 1},
{key: "3", name: "Menu #3", depth: 0},
{key: "3-1", name: "Menu #3-1", depth: 1},
{key: "3-1-1", name: "Menu #3-1-1", depth: 2},
{key: "3-1-2", name: "Menu #3-1-2", depth: 2},
{key: "3-2", name: "Menu #3-2", depth: 1},
];
/*
let submenu1 = [];
let menu1 = null;
menutable.forEach((item) => {
if(item.key === "2") {
menu1 = item;
return true;
}
if(menu1) {
if(menu1.depth < item.depth) {
submenu1.push(item.name);
} else {
return false;
}
}
});
console.log("forEach : " + JSON.stringify(submenu1));
// forEach : ["Menu #2-1","Menu #2-1-1","Menu #2-1-2","Menu #2-2","Menu #3-1","Menu #3-1-1","Menu #3-1-2","Menu #3-2"]
*/
let submenu2 = [];
let menu2 = null;
menutable.some((item) => {
if(item.key === "2") {
menu2 = item;
return false; // continue
}
if(menu2) {
if(menu2.depth < item.depth) {
submenu2.push(item.name);
} else {
return true; // break
}
}
});
console.log("some : " + JSON.stringify(submenu2));
// some : ["Menu #2-1","Menu #2-1-1","Menu #2-1-2","Menu #2-2"]
참고 자료
'Tips, Tricks > Node, Vue, Electron' 카테고리의 다른 글
Ubuntu 에 LTS버전의 Node.js 설치하기(Installing LTS version of Node.js on Ubuntu) (0) | 2023.03.09 |
---|---|
Vue.js에서 동적 컴포넌트 사용하기(Dynamic Components in Vue.js) (0) | 2020.05.11 |
Vue.js에서 resize이벤트 처리하기 (0) | 2020.05.07 |
Vue.js : 입력양식 배열 사용하기(v-model array with Multiple Input) (0) | 2020.03.24 |
Vue.js Filter : 3자리마다 쉼표찍기와 bytes 길이 자동 표시(Pretty currency & Pretty size of bytes) (0) | 2020.03.10 |