JavaScript/DreamCoding

Arrow Function에 대해서

느리지만 꾸준하게 2021. 8. 2. 19:28

프로그램안에서 저마다의 기능을 수행하는 함수들이 있는데 절차적 언어같은 경우는 함수가 프로그램에서 중요한 기능을 담당한다.(자바스크립트도 프로시저 언어에 속한다.) 즉 sub-program이라고 부르는데 프로그램 안에서 각각의 작은 단위들을 수행하는 것이 function이다.

function은 대체적으로 input x을 잘 처리한 다음에 output f(x)로 리턴을 하는 것이 function이다. 언어자체에 존재하는 function을 쓸 때 API(Application Programming Interface)를 쓸 때 FUNCTION f: 함수의 이름을 보고 함수의 기능을 파악하게 된다. 전달해야되는 파라미터들이 무엇인지 어떤값이 리턴되는 것을 기대하는 지 이러한 interface를 보면서 이러한 일들을 수행하겠구나라고 예상할 수 있다. 그래서 함수에는 input과 output이 중요하다. function의 이름을 정하는 것이 매우 중요하다.

 

function은 프로그램을 구성하는 굉장히 기초적인 빌딩블럭이고

재사용이 가능하고 subprogram이라고 불린다. 한 가지의 태스크나 어떠한 값을 계산하기 위해서 쓰여진다.

자바스크립트에서 function을 정의하는 방법은 키워드를 이용해서 함수의 이름을 지정한 다음에 파라미터를 쭉 나열한 다음 함수안의 기본적인 비즈니스 로직을 작성한 다음에 리턴을 해주면 된다. 여기서 하나의 함수는 한 가지의 일만 하도록 만들어야 한다.

 

그리고 함수의 이름을 작성할 때는 커맨드 형태 즉 동사형태로 지어야 한다.

함수의 이름을 정하기 어렵다면 함수안에서 너무 많은 것들을 하고 있지는 않은지 생각해볼 필요가 있다.

함수의 이름을 세분화 해줄 필요도 있다(createCardAndPoint => createCard, createPoint)

그리고 자바스크립트에서 function은 오브젝트이다. 오브젝트이기 때문에 function을 변수에다가 할당할 수도 있고 파라미터로 전달이되고 함수를 리턴할 수 있게 된다.

 

함수가 정의된 걸 보면

function이라는 키워드를 쓰고 함수의 이름은 printHello이고 콘솔에 hello를 출력하게 된다. 이 함수는 계속 hello만 출력하기 때문애 쓸모가 없다.

좀 더 유용한 함수를 만들려면 파라미터로 메세지를 전달하면 전달된 메세지를 화면에 출력하도록 만드는 것이 좋다. 

자바스크립트에서는 타입이 없기 때문에 함수자체의 인터페이스만 봤을 때 메세지가 스트링을 전달해야하는지 숫자도 전달해야하는지 명확하지 않다. 그래서 아래와 같이 숫자를 전달할 수도 있다.(숫자가 문자열로 변환되어서 출력)

 

타입스크립트로 쓰게 되면 typescript에서는 type을 안적었다고 컴플레인 된다. 그래서 string이라고 명시해주면 에러가 없어진다. 그래서 타입스크립트에서는 파라미터나 리턴타입을 명시하도록 되어있다. 리턴을 number로 하고 싶으면 또 컴플레인 된다. 그래서 리턴값을 숫자로 하면 컴플레인이 사라진다. 그리고 변환된 자바스크립트에서는 타입이 없다.

그래서 규모있는 프로젝트를 하거나 현업에서 작성한것을 라이브러리형태로 API를 제공해야 할 때 타입스크립트를 쓰는게 조금 더 명확하고 쉽게 만들어 준다. 함수에 인터페이스만 봐도 정확하게 무엇을 하는 것인지 함수에 함수의 이름과 전달되어야 할 파라미터, 데이터타입, 어떤값이 리턴되는지를 확실하게 확인하고 쓸 수 있기 때문이다.

 

반대로 자바스크립트에서는 인터페이스가 정확하게 명시되어져 있지 않아서 프로그래밍 할 때 많은 문제가 있다.

 

두 번쨰로 function에 전달되는 parameters들은

premitive 타입같은 경우에는 메모리에 value가 그대로 저장되어 있기 때문에 value가 그대로 전달이 되고 object타입 같은경우 메모리에 레퍼런스가 저장되어져서 레퍼런스가 전달되어진다.

아래 그림을 보면 changeName이라는 function은 전달된 obj의 이름을 coder로 무조건 변경하는 함수이다. 그래서 jay라는 const를 정의한 다음에 jay라는 오브젝트를 만들어서 할당해주면 메모리에는 오브젝트가 만들어진 레퍼런스가 들어가게 되고 레퍼런스는 오브젝트를 메모리 어딘가에 가리키고 있다. 

 

changeName jay을 전달하게 되면 전달된 jay. jay가 가리키고 있는 곳에 이름을 coder로 변경하게 된다. 그래서 출력하게 되면 coder로 변경되게 된다. 그래서 오브젝트는 레퍼런스로 전달되기 때문에 함수안에서 오브젝트의 값을 변경하게 되면 그 변경된 사항이 그대로 메모리에 적용되기 때문에 나중에 추후에 변경된 사항들을 확인 가능하다.

 

세 번째로는 Default Parameters인데 ES6에 추가되어졌다.

showMessage라는 것을 보면 message와 from 두가지 파라미터를 받아온다. 그래서 메세지가 누구로부터 받아왔는지 출력을 하게 되는데 여기서 showmessage를 출력할 때 하나만 메세지를 전달된 걸 볼 수 있는데 메세지는 출력이 잘 되지만 from이 정의되어져 있지 않기 때문에 undefined로 나오게 된다. 

그래서 예전에는 파라미터가 전달되지 않을 경우를 대비해서 from이 undefined이면 unknown으로나오게 하자해서 아래콘솔창과 같이 나오게 할 수 있다. 

위에처럼 귀찮게 작성안하고 아래와 같이 간단하게 나타낼 수 있다.

 

네 번째는 Rest Parameters인데 이거도 ES6에 추가된 것이다. 

... 세개를 작성하게 되면

Rest parameters라고 불리는데, 배열형태로 전달되게 된다. 그래서 printAll이라는 함수를 호출할 때 인자를 총 세개를 전달했는데 ...args는 총 세개의 값이 담겨져 있는 배열이다. 그래서 배열형태로 전달이 되는거고 for loop를 이용해서 처음부터 arg의 개수만큼 돌면서 차례대로 출력이 된다. 

 

배열 같은거 출력할 때 간단하게 for of라고 출력할 수도 있다. 

더 간단하게는 배열에 forEach 함수형 언어를 이용해서 출력할 수도 있다.

 

function은 오브젝트의 일종이다라고 했는데 printAll이라는 함수를 선언했을 때 .을 누르면 오브젝트로 전환이 되기 때문에 printAll의 속성값을 확인할 수 있다. 

다섯번째로는 Local Scope에 대해서 {} block scope와 global scope에 대해서 저번에 알아봤는데 한 문장으로 정리하면

 

"밖에서는 안이 보이지 않고 안에서만 밖을 볼 수 있다."

 

블록{}안에 함수나 if안에서 변수를 선언하게 되면 그것은 지역변수이다. 지역변수는 지역적이기 때문에 안에서만 접근이 가능하고 만약에 메세지를 밖에서 출력하게되면 에러가 발생한다.

하지만 안에서는 globalMessage라는 것을 볼 수도 있고 출력도 가능하다.

 

이 원칙은 어느곳에서나 적용이 가능한데

함수안에서 또 다른 함수를 선언할 수 있는데 printMessage라는 함수안에 printAnother이라는 또 다른 함수가 있는데 똑같은 원칙에 입각해서 자식은 부모에게서 정의된 메세지들을 확인할 수가 있다.

하지만 자식안에 정의된 childMessage를 바로 부모 상위 위에서 보려고 하면 에러가 발생한다.

그래서 아까 문구처럼 자바스크립트에서 스코프란 안에서만 밖을 볼 수 있다의 개념을 생각하면서 학습하면 된다.

함수에서는 파라미터들을 전달받아서 계산된 값을 리턴할 수 있다. sum이라는 함수를 호출하면 1 2를 더해서 3이 호출되는데 리턴타입이 없는 것들은 return undefined;이 들어가있는것과 같다.(생략가능)

 

 

다음으로 Early Return을 해라 early exit을 해라라고 하면 upgradeUser이라는 함수안에서 user의 point가 10이상일 경우에만 무언가 업그레이드를 진행해라는 로직이 있다면 블럭안에서{} 로직을 작성할 건데 그러면 가독성이 떨어진다. 

그런경우에는 if와 else를 번갈아 쓰지말고 조건이 맞지 않을때는 빨리 return을 해서 함수를 종료하고 조건이 맞을 때만 그다음에 필요한 로직들을 실행하는 것이 좋다.

 

지금까지 function을 어떻게 선언하는지에 대해서 알아봤는데 이제 function expression에 대해서 알아보면

first-class function이라고 하면 다른변수와 마찬가지로 변수에 할당이 되고 function에 파라미터로 전달이 되며 리턴값으로도 리턴이 된다. 그것이 가능한 것이 function expression인데 함수를 선언함과 동시에 print에 할당하는 것을 볼 수 있는데 function에 아무 이름이 없고(anonymous function) function이라는 키워드를 이용해서 파라미터와 블럭을 이용한 것을 아래와 같이 볼 수 있다.

 

이렇게 함수를 print에다가 할당하게 되면 print라는 변수에 함수를 호출하듯이 호출하게되면 print가 호출하게 되고 다시 다른 변수에 또 할당하게 되면 다시 함수를 호출하는 거 처럼 부르면 print가 호출하게 된다. 그리고 위에서 sum이라는 function을 만들었는데 다시 변수에 할당하게 되면 4가 출력되는 것을 볼 수가 있다. 

즉 function expression은 할당된 다음부터 호출이 가능한 반면에

function declaration은 hoisting이 된다. var hoisting에서 알아봤듯이 함수가 선언되기 이전에 호출해도(sum이라는 함수를 정의하기도 전에 sum(2, 3);을 찍어도 된다는 것이다.(js엔진이 선언된것을 제일 위로 올려주기 때문)

Callback에 대해서 알아보면

randomQuiz에 3개의 인자가 있자가 있는데 상황에 맞게 출력해달라는 것이 callback함수라는 것이다.  두 가지의(printYes, printNo) 콜백함수가 파라미터로 전달되어서 답이 러브유일 경우에만 printYes를 출력하라고 하고

아니면 printNo를 출력하라고 한다. 

아래를 보면 printYes라는 변수에 yes를 출력하는 함수를 할당해 놓고 printNo라는 변수에는 no를 출력하는 함수를 할당해 놓았다. 그래서 이렇게 정답이 맞으면 printYes를 출력하고 아니면 printNo를 출력하게 되어 no와 yes가 출력된 것을 볼 수 있다. printYes에는 anonymous function이 쓰여진 걸 볼 수가 있는데 printNo에는 함수이름이 print라고 지정이 되어져 있다. 

 이제 Arrow Function을 살펴보면

arrow function은 함수를 간결하게 만들어주는 것이다. arrow function은 항상 이름이 없는 anonymous function이다. 

function expression을 쓰게되면 {}도 써야하고 function이라는 키워드도 써야하지만 arrow function은 그럴 필요가 없다.

만약에 블록이 필요하다면 아래그림과 같이 쓰면 된다. 대신에 블록을 쓰게되면 return이라는 키워드를 꼭 넣어줘야 한다.

다음으로 IIFE에 대해서 알아보면

함수를 선언하게 되면 따로 함수를 호출해줘야 하는데 IIFE는 선언함과 동시에 ()묶어서 ()를 써주면 바로 함수가 호출이 된다. 최근에는 잘 사용되지 않지만 자바스크립트에서 함수를 바로바로 쓰고 싶을 때 유용하다.

퀴즈를 한번 풀어보면

function calculator을 만들어서 입력받은 커맨드의 따라서 a, b의 숫자값을 + - * /를 해보자

 

 

 

 

 

 

 

참고: https://www.youtube.com/watch?v=e_lU39U-5bQ&list=PLv2d7VI9OotTVOL4QmPfvJWPJvkmv6h-2&index=5