1. 함수는 무엇인가요?


1-1. 함수는 원하는 작업을 수행하기 위해 만들어 놓은 코드 블록입니다.

function myfunc(a, b){
  a += b;
  return a;
}

let a = 10, b = 3;
function foo(a, b) {
    a = 32;
    b = 'hi';
}
foo(a, b);                                    // 매개변수에 값을 입력
console.log(`a의 값 ${a}, b의 값 ${b}`);      // a의 값 10, b의 값 3 출력
                                              //foo 함수 밖의 a, b 변수는 값이 바뀌지 않는다.


let object = { a: 10, b: 3 };
function boo(object) {
    object.a = object.a + object.b;
    object.b = 'hi';
}
boo(object);                                           // 매개변수에 객체를 입력
console.log(`a의 값 ${object.a}, b의 값 ${object.b}`); // a의 값 13, b의 값 hi 출력
                                                       //boo 함수 밖의 object 객체의 속성들의 값이 바뀐다 
  • 매개변수가 기본 자료형이라면 값이 함수에 전달됩니다.
  • 따라서 함수 내부에서 매개변수의 값을 변경하더라도 함수 밖에는 반영되지 않습니다.
  • 매개변수가 객체라면 객체의 주소값이 함수에 전달됩니다.
  • 따라서 함수 내부에서 매개변수가 가리키는 객체의 속성을 변경하다면 함수 밖의 객체를 변화시킬 수 있습니다.

1-2. 함수도 객체입니다.

function foo(){
  return console.log('foo 함수 호출');
}

foo();            // foo 함수 호출. 'foo 함수 호출' 출력
let a = foo;      // foo 함수의 주소값을 변수 a에 참조
a();              // 변수 a는 foo 함수를 참조하고 있으므로 foo 함수 호출 가능. 'foo 함수 호출' 출력
  • 함수를 호출하기 위해서는 함수 이름 뒤에 괄호()를 붙힙니다.
  • 함수 이름은 함수를 참조하는데 사용할 수 있습니다.

2. ES6 이전에 함수를 표현하는 방법은?


2-1. 함수 표현식과 함수 선언

// 함수 선언
function foo() { }

// 함수 표현식
const foo  = function() { } // 익명함수를 변수 foo에 참조
  • 함수를 표현하는 방법에는 함수 선언과 함수 표현식이 있습니다.
  • 함수 표현식은 함수의 이름이 없는 익명함수를 변수에 할당하는 방식입니다.

2-2. 함수 표현식과 함수 선언의 다른점

foo();        // foo 함수 호출 가능
boo();        // boo 함수 호출 불가능

function foo() {
  console.log('foo 호출');
}

var boo = function() {
  console.log('boo 호출');
};
//////////////////////////////////////////////
// 호이스팅된 모습
function foo() {            // foo 함수 전체가 위로 끌어올려짐
  console.log('foo 호출');
}
var boo;    // boo 변수에 할당된 값이 없음
foo();        // foo 함수 호출 가능
boo();        // boo 함수 호출 불가능

var boo = function() {
  console.log('boo 호출');
};
  • 함수 선언은 스코프의 최상단으로 호이스팅됩니다.
  • 반면 함수 표현식은 호이스팅 되지 않습니다.
  • 따라서 함수 표현식으로 선언된 함수는 함수 표현식을 선언하기 전에는 함수를 호출할 수 없습니다.

3. 화살표 함수는 무엇이 다른가요?


3-1. 함수를 표현하는 것이 더 간단해졌습니다.

const func1 = function() { const num = 10; };
const func1 = () => { const num = 10; }; // function 키워드 생략 가능

const func2 = function(num) { 
  for(let i = 0; i < 10; i++) { num++; }
  return num;
};
const func2 = num => {                    // 함수의 매개변수에 괄호 생략 가능
  for(let i = 0; i < 10; i++) { num++; }
  return num;
};

const func3 = function (num) { return `입력된 숫자는 ${num}입니다.`; };
const func3 = num => `입력된 숫자는 ${num}입니다.`; // 중괄호와 return 문 생략 가능
  • function 키워드를 생략할 수 있습니다.
  • 함수의 매개변수가 1개라면 괄호()를 생략할 수 있습니다.
  • 함수 바디가 표현식 하나라면 중괄호와 return 문을 생략할 수 있습니다.

3-2. 화살표 함수는 항상 익명함수입니다.


3-3. 화살표 함수는 this가 정적으로 묶입니다.

  • ES6 이전의 일반적인 함수를 사용할 경우

    const o = {
      name: 'javascript',
      m: function () {
          console.log('m함수 호출==============');
          console.log('this.name은?', this.name);        // javascript 출력
          console.log('this는 객체 o? ', this === o);    // true 출력
          console.log('this는 전역객체? ', this === global)    // false 출력
          function foo() {
              console.log('foo함수 호출==============');
              console.log('this.name은?', this.name);    // undefined 출력
              console.log('this는 객체 o? ', this === o);    // false 출력
              console.log('this는 전역객체? ', this === global)    // true 출력
          }
          foo(); // 함수 형태로 호출
      }
    };
    o.m();    // 메서드의 형태로 호출
    const f = o.m;
    f();    // 이런 방식으로 호출된다면?
    • this 키워드는 변수나 속성 이름이 아닙니다.
    • this 키워드에는 값을 할당할 수 없습니다.
    • 만약 중첩함수가 메서드 형태로 호출되면, 중첩함수의 this 값은 그 함수가 속한 객체입니다.
    • 만약 중첩함수가 함수 형태로 호출되면, 중첩함수의 this 값은 전역객체(일반모드) 또는 undefined(strict mode) 중 하나입니다.
  • 화살표 함수를 사용할 경우

    const o = {
      name: 'javascript',
      m: function () {
          console.log('m함수 호출==============');
          console.log('this.name은?', this.name);              // javascript 출력
          console.log('this는 객체 o? ', this === o);          // true 출력
          console.log('this는 전역객체? ', this === global)    // false 출력
          const foo = () => { // 화살표 함수 사용
              console.log('foo함수 호출==============');
              console.log('this.name은?', this.name);          // javascript 출력
              console.log('this는 객체 o? ', this === o);      // true 출력
              console.log('this는 전역객체? ', this === global)    // false 출력
          }
          foo();
      }
    };
    o.m();
    • 화살표 함수를 사용하면 중첩함수 안에서 this를 사용할 수 있습니다.
    • 화살표 함수는 전역 컨텍스트에서 실행될 때 this를 새로 정의하지 않습니다.
    • 대신 코드에서 바로 바깥의 함수 또는 클래스의 this 값이 사용됩니다.

3-4. 객체 생성자로 사용할 수 없습니다.

const Foo = () => {};
const foo = new Foo();        // 에러 발생

3-5. arguments 변수를 사용할 수 없습니다.

더 공부해볼 부분

  • 함수형 프로그래밍
  • call, apply, bind
  • 클로저
  • 고차함수

참조