드림코딩_by엘리/유투브강의_JavaScript

드림코딩 by 엘리_ Arrow Function은 무엇인가? 함수의 선언과 표현

AngeRay 2021. 9. 6. 21:50

Function


프로그램 안에서도 각각 저마다의 기능을 수행하는 함수들이 있다.

절차적인 언어같은 경우 함수가 프로그램에서 굉장히 중요한 기능을 담당한다.

바스크립트에서 function은 굉장히 중요한 기능을 하기때문에

sub-program 이라고 부른다.

프로그램 안에서 각각의 작은 단위의 기능들을 수행하는 것이 바로 function 이다.

 

 

input prameter를 받아서이것들을 잘 처리한 담에 

output return을 하는것이 function 이다.

함수의 이름을 보고 '이 함수는 이런일을 하겠구나' 하고 생각가능하고

그리고 전달해야 될 parameters이 무엇인지?

어떤 값들이 return 되기를 기대가능한지?

이런 interface들을 보고서 이런 일들이 수행가능 하겠구나 하고 예상 가능하다.

따라서 함수는 input, output, 함수명이 중요하다.

 

함수는 프로그램을 구성하는 굉장히 기본적인 빌딩 블럭이다.

sub-program 이라고도 불리며 여러번 재사용이 가능하단 장점이 있다. 

한 가지의 task나 아니면 어떠한 값을 계산하기 위해 쓰여지고 있다.

 

자바스크립트에서 함수정의 방법은 

function 이라는 키워드를 이용하고 함수이름 지정 후 (파라미터들을 나열한 다음) {함수안에 기본적인 비즈니스 로직을 작성한 다음 return을 해주면 된다.}

 

여기서 중요한것은 하나의 함수는 한가지의 일만 하도록 만든다.

그리고 함수명 작성 시 함수는 무언가를 동작하는 것이기 때문에 동사 형태로 이름을 지정해야 한다.

함수의 이름을 정하기가 너무 어렵다면 

혹시 내가 이 함수안에서 너무 많은 것들을 하고 있지않은지 생각해 볼 필요가 있다.

복잡한 함수명을 조금 더 세분화해서 나눌 구 있지 않을지 조금 더 고민을 해보면 함수를 깨끗하게 만들 수가 있다.

 

자바스크립트에서 함수는 object 이다.

object로 간주되기 때문에 function은 변수에다도 할당 가능하고,

파라미터로 전달되고, 함수를 return 할수도 있게 되는 것이다.

함수 선언시 .을 누르면 함수가 obj로 전환되기에 해당 함수의 속성값들이 확인 가능하다.

함수를 잘 정의했다면 함수를 호출가능하다.

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

 

자바스크립트 에서는 타입이 없다.

그렇기 때문에 함수 자체 인터페이스만 보았을 때

메세지가 string을 전달 해야되는지, 숫자를 전달 해야되는지 명확하지 않다.

다른 함수에서 type이 중요한 경우에는 자바스크립트는 조금 난해할 수 있다.

 

**

타입스크립트에서는 파라미터와 리턴타입에 타입을 명시하도록 되어 있다.

함수의 인터페이스만 봐도 이 함수가 정확히 무엇을 위한 함수인지 알 수있기 때문이다.

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

 

Parameters 

function에 전달되는 parameters

primitive type 같은 경우 메모리에 value가 그래도 저장었기 때문에 value가 전달되고,

object 경우 메모리에 ref가 저장되기 때문에 그래서 ref가 전달된다.

 

changeName()은 전달된 obj에 이름을 coder로 변경시켜준다.

ellie라는 const 정의 후 ellie라는 obj를 만든 후 할당해주면 메모리에는 obj가 만들어진 ref가 메모리에 들어가게 되고  

이 ref는 이 obj를 메모리 어딘가에 가리키고 있다.

obj는 ref로 전달되기 때문에 함수안에서 obj의 값을 변경 하게되면

그 변경된 사항이 그대로 메모리에 적용 되기에  나중에 추후에 변경된 사항들이 확인 가능하다.

 

Default Parameters

showMessage()는 두가지의 파라미터들을 받아온다.

하지만 전달인자는 하나만 있기에 undefined가 뜬다.

그래서 예전에는 파라미터 값이 전달되지 않을 경우를 대비했다.

하지만 이제는 파라미터 옆에 원하는 default값을 지정해 놓으면 사용자가 파라미터를 전달하지 않을 때

이 값이 대체되어서 사용된다.

function showMessage(message, from = 'unknown') {

    console.log(`${message} by ${from}`);

}

 

// function showMessage(message, from) {

//     if(from === undefined) {

//         from === 'unknown';

//     }

// } 예전에는 parameter값이 전달되지 않았을때를 생각해 코드를 작성했다.

 

showMessage('hi'); // 전달인자 하나면 parameter로 전달

 

Rest Parameters

파라미터로 ... 을 작성하게 되면 rest parameters라고 불리는데 이것은 바로 배열형태로 전달되게 된다.

배열 출력시 for loop를 이용할 수 도 있지만 간단하게 출력도 가능하다.(해당 내용은 array에서 다시 학습)

 

Local scope 

 

자바스크립트에서 scope란 유리창에 tint가 처리된거랑 같다.

안에서는 밖이 보이지만 

밖에서는 안을 볼수없고 접근이 안된다.

그리고 중첩된 함수에서 자식의 함수가 부모함수에 정의된 변수들을 접근이 가능한 것들이 바로 클로져이다. 

 

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

 

{

  이렇게 블럭안에서 변수를 선언하게 되면 이것은 지역변수 이다.

  지역변수는 지역적인 것이기 때문에 안에서만 접근이 가능하고

  만약에 메세지를 밖에서 출력하게 되면 error가 발생하게 된다.

 

  하지만 안에서는 global변수를 볼 수 있고 출력이 가능하다.

  함수안에서 함수를 또 선언 가능한데,

  자식은 부모에게서 정의된 변수들을 확인가능 하나,

  자식안에 정의된 변수들은 부모 상위위에서 볼려고 한다면 error가 발생한다.

}

 

return

함수에서는 parameters로 값들을 전달 받아서 계산된 값을 return 할 수 있다.

return type이 없는 함수들은 return undefined가 들어있는것과 같다. (생략이 가능하다.)

모든 함수는 return undefined 이거나 값을 return 할 수 있다.

 

early return, early exit을 하라고 코드 지적질을 받을 수 있는데 

{ }안에서 로직을 많이 작성하면 가독성이 떨어진다.

그래서 이런 경우에는 조건이 맞지 않을 경우에는 빨리 return을 해서 함수를 종료하고 

조건이 맞을 때만 그 다음에 필요한 로직들을 실행하는 것이 더 좋다.

 

조건이 맞지않는 경우, 값이 undefined인 경우, 값이 -1인 경우, 빨리 return을 하고

필요한 로직들은 그 뒤에 작성하는 것이 더 좋다.

 

여테까지 function을 어떻게 선언하는지를 알아봤는데 

이제는 function expression에 대해서 알아보자.

 

function expression

function은 다른 변수와 마찬가지로 변수에 할당이 되고  

function의 parameter로 전달이 되며

return값으로도 return이 된다.

그것이 가능하게 하는것이 function expression 이다.

 

함수를 선언함과 동시에 바로 변수에 할당했는데 

함수에 아무 이름이 없고, function이라는 키워드를 이용해서 parameter와 {}을 이용한것을 볼 수 있다.

함수에 이름이 없는것을 anonymous function 이라고 부른다.

함수의 이름 없이 필요한 부분만 작성해서 변수에 할당 가능하다.

그러나 우리가 원하면 함수의 이름을 지정 가능하다.

이렇게 이름이 있는 함수를 named function 이라고 한다.

이렇게 함수를 const print 변수에 할당하게 되면 print라는 변수를 함수를 호출하듯이 호출한다.

 

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

function declaration은 hoisted가 된다.

이 말은 함수가 선언되기 이전에 호출해도 호출이 가능하다.

이것은 자바스크립트 엔진이 선언 된것을 제일 위로 올려주기 때문이다.

 

Callback function

함수를 전달해서 상황에 맞으면 전달된 함수를 불러라고 하는것을 callback  function 이라고 한다.

두가지의 callback functions가 parameters로 전달된다.

(즉 printYes(), printNo() Callback function은 2개이다.)

 

printYes 변수에 yes!를 출력하는 함수를 할당하고,

printNo 변수에  no!를 출력하는 함수를 할당한다.그담에

randomQuiz 함수 호출시, answer과 printYes와 printNo callback functions 를 각각 전달하게 된다.

그래서 정답이 맞으면 yes!가 출력되고 아니면 no!가 출력된다.

 

function randomQuiz(answer, printYes, printNo) {

    if(answer === 'love it') {

        printYes();

    } else {

        printNo();

    }

}

const printYes = function() {

    console.log('yes!');

}

const printNo = function print() {

    console.log('no!');

}

 

randomQuiz('love it', printYes, printNo);

randomQuiz('wrong', printYes, printNo);

 

function expression에서 name을 쓰는 이유는 

우리가 디버깅을 할때 디버깅의 stack traces에 함수 이름을 나오게 하기위해 쓰는것이다.

 

 

함수안에서 자신 스스로 또 다른 함수를 호출할 때 함수안에서 함수가 계속 호출되면서 갯수가 늘어난다.

이렇게 함수 안에서 함수 자신 스스로를 부르는것을 recursion(재귀 : 어떠한 것을 정의할 때 자기 자신을 참조하는 것을 뜻한다.) 이라고 한다.

정말 필요할때 피보나치 수를 계산한다 던지, 반복되는 평균값을 계산한다 던지, 등등 쓰임새가 다양하다.

이렇게 함수를 무한대로 호출하게 되면 call stack이 가득찼다는 에러가 발생한다.

 

Arrow Function

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

function expression을 쓰게되면 function이라는 키워드, {}도 계속 써야되는 번거로움이 있는데

arrow function은 function이라는 키워드가 필요없고, {}도 필요없다.

한 줄에 묶어서 => arrow 이렇게만 표기하면 끝이다.

 

const simplePrint = function() {

    console.log('simplePrint!');

}

 

const simplePrint2 = () => console.log('simplePrint :)');

 

간결하게 쓸수있고, 나중에 함수형 프로그래밍 배열이나 리스트 같은 것을 볼 때 더욱더 빛을 발휘한다.

이렇게 한줄인 경우에는 {}없이 작성가능 하지만 

함수안에서 조금 더 다양한 일들을 해야 되서 {}이 필요할때도 작성가능하다.

대신 {}을 작성시 return이라는 키워드를 사용해서 return 해줘야한다.

 

IIFE(Immediately Invoked Function Expression)

함수선언시 나중에 따로 함수를 호출해줘야 하는데

하지만 선언함과 동시에 바로 호출하려면 함수의 선언을 괄호로 묶고 함수를 호출하듯이

작성해주면 바로 함수가 호출되는것이 확인 가능하다.

최근엔 잘 사용하지 않지만 자바스크립트에서 함수를 바로바로 실행하고 싶을 때 사용한다.

 

(function hello() {

    console.log('IIFE');

})();