728x90

중첩 함수는 나쁜 아이가 아니에요

대게 함수를 중첩 해서 사용은 가능은 하지만 잘 하지 않는다. 그런 이유는 코드가 복잡해지고, 코드가 난해하다는 느낌이 들기도 하기 때문이다.

하지만 중첩 함수가 괜찮은 친구처럼 보이는 경우는 언제일 수 있을까? 내가 생각했을 때엔 응집도를 고려했을 때가 아닐까 싶다.

보통 코드에 대한 응집도를 높이기 위해 관련 있는 코드끼리 모아두려고 한다. 그래서 클래스를 사용한다고 본다. 

그런데 클래스에 들어가는 함수에서, 함수를 호출하는 경우 코드가 복잡해지는 경향이 있다. 왜 그런가 싶으면 코드가 떨어져 있어 연결되어 있음을 볼 수가 없다.

그래서 코드를 파악하기 힘들다.

중첩 함수가 괜찮은 녀석인지 보기 위해 코드를 하나 봐보자.

function order(menu) {
    console.log(menu);
}
 
 
function brand(brandName) {
    switch(brandName) {
        case "ABC_Market":
            order("신발");
            break;
        case "Mart":
            order("음료수");
            break;
    }
}

위 코드와 같이 order가 계속 호출 되니 함수로 따로 빼서 쓰는 것이 맞다.

 

현재는 코드가 짧기 때문에, 그리고 작성한 이는 의도를 알지만, 코드가 길어지거나 다른 이가 보았을 때 코드를 이해하기 쉬울까?

order가 brand에서만 사용되는지 알 수 있을까? 확실하게!? 모를 것이다.

 

그래서 코드의 응집도를 높일 수가 있다.

function brand(brandName) {
    function order(menu) {
        console.log(menu);
    }
    switch(brandName) {
        case "ABC_Market":
            order("신발");
            break;
        case "Mart":
            order("음료수");
            break;
    }
}

남들이 보았을 때 거부감이 들 수 있으나 order 함수가 명확하게 brand에서만 사용이 됨을 알 수 있습니다.


Currying이 뭐에요? 먹는건가요?

 함수형 프로그래밍에서 나오는 개념으로, 기존의 복잡한 파라미터를 넘겨 복잡한 처리를 하는 함수를 읽기 쉬운 나누어진 코드로 변경하는 것을 말한다.

코드를 한번 봐보자.

function Hello(text) {
    return function (text2) {
        console.log(text, text2);
    }
}

이게 무슨 코드인지 너무 난해하다고 느낄 수 있다. 하지만 사용 방법은 더 난해하다.

코드를 보고 다 고개를 절레절레 지울 수 있는 으뜸한 코드가 완성되었다.

사실 그렇게 나쁘지 않아요 ( ╯□╰ )

함수를 호출 시에 파라미터를 저렇게 넘겨서 사용하니 정말 별로에 별로이지만 다음 호출 방법을 보면 생각이 조금 달라진다.

let hello_Name_To_Text = Hello("아무개님");
hello_Name_To_Text("안녕하세요");

이렇게 작성하니 뭔가 편해지는 느낌과 더불어 머리에 이런 방법도 가능하네?

기존에 불편하게 작성했던 코드를 쉽게 작성할 수 있을 것 같은 생각이 날 수 있다.

  • Partial Application은 Currying 방법을 다르게 부르는 동의어라고 보시면 됩니다.

기존에 하나의 함수에서 복잡하게 작성하였던 코드들이 잘게 분리되면서 복잡도가 낮아지며 코드가 유연해지는 쪽으로 사용하면 좋을 것이다.

  • 참고, 화살표를 사용한 코드 단축화

 코드가 중복적으로 들어가는 쓸데없는 코드를 보일러레이트 코드(Boilerplate code)라 부른다. 위 에서는 function과 return으로 코드가 장풍을 맞은 것마냥 들어가버린다.

이를 없앨 수 있는 방법은 화살표다. const로 변수처럼 함수를 사용할 때엔 Func를 붙이기를 추천하고, 아래 코드가 짧아지긴 했으나 더 헷갈릴 것 같다는 생각이 든다.

const Hello = text => text2 => {
        console.log(text, text2);
}

왜 갑자기 확장 함수가 떠오를까?

위 코드들을 보다 보면 확장 함수가 생각난다. 코틀린에서 확장 함수를 지원해주는데 뭔가 위 코드와 비슷한 것 같은 느낌이 든다.

fun List<Int>.getHigherThan(num: Int): List<Int> {
    val result = arrayListOf<Int>()
    for (item in this) {
        if (item > num) {
            result.add(item)
        }
    }
    return result
}
 
fun main() {
    val numbers: List<Int> = listOf(1, 2, 3, 4, 5, 6)
    val filtered = numbers.getHigherThan(3).toString()
    System.out.println(filtered)
}

확장 함수는 다음 코드와 같이 돌아간다.

눈 여겨 볼만한 것은 List<Int>라는 타입에 getHigarThan을 넣었다는 점이다.

기존이었다면 getHigherThan 함수를 만들고 getHigherThan(numbers, 3).toString()으로 호출했을 것이다.

 numbers.getHigherThan(3).toString() 코드에 비해  getHigherThan(numbers, 3).toString()은 어디로부터 시작하는지 명시가 되어있지 않는다는 느낌이 든다.

정리

위 모든 코드들이 코드를 단순하게 만들기 위한 기법이라 생각한다. 생소하지만 어느 한 구석 잘 적용한다면 유지 보수하기 좋은 코드가 탄생할 것일까 말까 아무도 모른다.

 

 
반응형

'코딩 관련 > 자바스크립트' 카테고리의 다른 글

generator function  (0) 2023.10.19
getDay(), getDate()  (0) 2023.10.19
Map 섞어 쓰면 에러 발생  (0) 2023.10.19
Javascript Template literal  (1) 2023.10.19
배열 초기화 & Json 값만 배열로 변경하기  (0) 2023.10.19
728x90

Java의 Iterator와 비슷한 느낌을 갖는 function이다. 표기법으로는 function 또는 function 으로 자신이 쓰고 싶은 방법대로 작성하면 된다.

왜 Iterator와 비슷한가? 보통 Iterator는 Collection에 들어가며, 내가 넣은 요소를 탐색하는 요소로 사용된다.

function에도 동일하게 내가 요소(구간)을 만들어 다음 로직의 요소(구간)을 실행할 수 있도록 function을 실행 구간을 블록킹할 수 있게 된다.

function* goStop() {
	console.log("go");
	yield "Stop";
	console.log("go2");
	yield "Stop2";
}

function* generateName() {
  yield 'W';
  yield 'O';
  yield 'N';
  yield 'I';
  yield 'S';
  yield 'M';
}

// for..of
const genForForOf = generateName();
for (let i of genForForOf) {
  console.log(i);
}

이터러블하기 때문에 of에 넣어도 동작한다.

어느 상황에서 유용할까?

모질라 페이지에서는 아래와 같이 설명한다.

Generators in JavaScript — especially when combined with Promises — are a very powerful tool for asynchronous programming as they mitigate — if not entirely eliminate -- the problems with callbacks, such as Callback Hell and Inversion of Control. However, an even simpler solution to these problems can be achieved with async functions.

비동기 프로그래밍에서 유용하다고 하는데 나는 다음과 같이 생각한다.

  • 여러 번에 걸쳐서 실행되어야 하는 하나의 로직 단위

우리는 보통 아토믹하게 작은 단위로 함수를 만들고 이를 조합해서 사용하며, 이는 재사용성에 의해 코드의 복잡도가 낮아진다고 말한다. 하지만 제너레이터 함수에 의해 함수의 동작을 내가 로직 단위로 쪼개서 조작할 수 있다.

로직은 하나의 흐름이지만, 로직 중간 중간 어느 시점에 이어서 진행되어야 하는 시점이 있다면 어떻게 될까?

일상 생활에 예를 들어보자.

나는 컴퓨터를 켜서 C언어를 공부한다고 생각하자.

C언어의 하나의 챕터를 공부하는 function* studyForC() {} 수행 중 이다.

하지만 모든 시간 내가 온전히 C언어를 공부하는 것이 아니다. 중간 중간 화장실에 가야 하기도 하고, 물도 마셔야 한다.

함수 실행의 주체를 공부가 아닌 나로 바꿔서 로직을 실행한다고 해보자.

javscript function Human() {

// studyForC.next() 시작 0~9페이지

// 화장실

// studyForC.next() 10~19페이지

// 물마시기

// studyForC.next() 20~29페이지

}

만약에 이를 제너레이터 함수가 아닌 다른 방법으로 실행했어야 했다면, 화장실 갔다 온 뒤 Callback함수로 넘겨 매 행위를 정해줘야 했을 것이다.

다른 언어에서 이런 함수를 제공하는지는 모르겠지만, 자바스크립트는 역시 난해하고 이상한 친구인듯 하다.

 

반응형
728x90

getDate 은 설정한 날짜를 가져온다.

getDay 는 로컬날짜를 가져온다.

그렇기에 getDay()로 가져오면 값이 다르게 나올 수 있으므로 getDate()를 사용할 때가 있다.

반응형
728x90

const m = new Map();

m['a'] = 1234;

m['a'] -> 1234

m.has('a'); -> false

m.set('b');

m['b'] -> undefined

바로 대괄호로 넣어버리면 has를 이용하지 못한다.

set으로 넣은 것을 [ ] 로 가져오지 못한다.

반응형

'코딩 관련 > 자바스크립트' 카테고리의 다른 글

generator function  (0) 2023.10.19
getDay(), getDate()  (0) 2023.10.19
Javascript Template literal  (1) 2023.10.19
배열 초기화 & Json 값만 배열로 변경하기  (0) 2023.10.19
페이지 재로딩 시 상단 이동  (0) 2023.10.19
728x90
  • ES6에서 나온 문법 중에 Template Literal이라고 있다.

백쿼터 `

`란 백쿼터를 사용하는 문법으로 대게 줄바꿈 문자열을 간단하게 사용할 때 사용한다.

예를 들어서

<ul>

    <li>HI</li>

</ul>

를 기존에는

let template = '<ul>' + '<li>HI</li>' + '</ul>';

let template = '<ul>\n<li>HI</li>\n</ul>';

으로 사용했다.

let template = '<ul>\
<li>HI</li>\
</ul>';

이것도 가능하긴 하다.

 

ES6에서는 

let template = `

<ul>

    <li>HI</li>

</ul>

`;

이 가능하다.

TEMPALTE LITERAL

const hello = "hello";

let template = `

<ul>

    <li>${hello}</li>

</ul>

`;

문자열에 바로 변수가 넣는 것이 가능하다.

응용 변수만 넣을 수 있나?

아니다.

let friends = [{name:'라이언',age:5},{name:'라이언2',age:2},{name:'라이언3',age:3}];

let template = `<ul>${friends.map( freind => `<li>이름:${freind.name} , 나이: ${freind.age}</li>`).join('\n')}</ul>`

결과물: '<ul>\n<li>이름:라이언 , 나이: 5</li>\n<li>이름:라이언2 , 나이: 2</li>\n<li>이름:라이언3 , 나이: 3</li></ul>'

놀랍게도 변수에 map이나 forEach등이 가능하니 응용이 다채로울듯하다.

응용: 동적 할당


웹 사이트의 경우 동적으로 할당되는 요소들이 많은 데, 이 HTML을 관리하는 것이 쉽지는 않다. 

숨어있다는 표현이 올바를 것 같은데, 어느 곳에 있는지 찾기가 어려울 때가 빈번하게 있다.

 

이런 부분들이 모여 코드 개발 속도를 저하되게 만드는데 이를 해결 방법이 있다.

물론 위 문법으로 해결한다기 보다는 Dom요소에 기대에 해결한다는 것이다.

<script id="selector">
    `<ul>${friends.map( freind => `<li>이름:${freind.name} , 나이: ${freind.age}</li>`).join('\n')}</ul>`
</script>
 

Html 문서 내 body 태그 뒤에 이 script를 넣어둔다.

그리고 해당 태그 요소를 Dom으로부터 가져와서 js로 실행하면 동적 할당 시에 유용하게 사용할 수 있다.

let b = eval(`<ul>${friends.map( freind => `<li>이름:${freind.name} , 나이: ${freind.age}</li>`).join("\n")}</ul>`);
 
eval이란 마음에 들지 않는 요소를 이용한다는 점이 꺼림직하지만, 쓸 수 있는 수단을 모두 사용해서 해결한다는 점이 인상적이다.
반응형
728x90

배열 초기화

arr.length = 0;

 

Json 값만 배열로 변경

Object.values(json);

반응형
728x90

페이지를 아래로 스크롤한 상태에서 재로딩하면 그 자리 그대로 로딩하게 되는데 이런 구현 방식은 브라우저 해주지 않을까..? 

그런 불확실성에서 페이지 로딩 시 상단으로 무조건 로딩되어야 한다면 아래 코드를 추가하면된디.

window.addEventListener('beforeunload', function () {
    // 최상단으로 스크롤 이동
    window.scrollTo(0, 0);
});

해당 코드를 통해 페이지가 로딩되는 것을 고려하지 않아도 자동으로 재로딩시 상단 이동이 되어 편리하다.

반응형
728x90

console.log() 만 사용하는 당신 조금 더 목적에 맞는 함수를 사용해보는 것은 어떨까요?

일단 먼저 json을 테이블 형태로 찍는 

console.table()을 사용해보세요!

더 많은 정보는 아래 글에서 확인해보시길

- https://javascript.plainenglish.io/its-2022-please-don-t-just-use-console-log-anymore-217638337c7d

반응형

+ Recent posts