함수 표현식 VS 함수 선언식

Dean H. Park·2020년 8월 12일
23

JS

목록 보기
2/8
post-thumbnail

잠깐! 🙌🏻

함수 선언식이란?

변수 선언이 var로 시작해야하는 것처럼 함수 선언은 function으로 시작한다.

선언 된 함수는 나중 사용을 위해 저장되며, call 될 때 실행된다.

function foo() {
	return "이것은 함수입니다.";
}

함수는 여기서만 선언되며, 사용하려면 해당 함수 이름을 호출하면 된다.

foo();	// "이것은 함수입니다."

함수 표현식이란?

자바스크립트 함수는 표현식을 사용하여 정의 될 수 있으며, 함수 표현식은 변수로 저장될수 있다.

var x = function (a, b) {return a * b};

함수 표현식이 변수에 저장되면, 변수는 함수처럼 사용 가능해진다. 변수에 저장된 함수는 함수명이 필요 없으며, 변수 이름을 통하여 호출된다.




함수 표현식 VS 함수 선언식

함수 표현식

alert(foo()); // 에러 발생! foo 함수는 아직 로드안됨
var foo = function() { return 5; }

함수 선언식

alert(foo()); 
// Alerts 5. 
// 선언 전에 호출되도 정상 동작

function foo() { return 5; }

함수 선언식은 코드가 실행되기 전에 로드되지만, 함수 표현식은 인터프리터가 해당 코드 줄에 도달 할 때만 로드된다.

함수 선언식은 var 문과 유사하게 호이스팅(호이스팅 이란?) 된다. 반면, 함수 표현식은 호이스팅되지 않으므로 정의 된 범위에서 로컬 변수의 복사본을 유지할 수 있다.

일반적으로 함수 선언식과 함수 표현식은 함께 사용할 수는 있지만, 함수 표현식은 함수 이름이 필요없기에 가독성이 더 높은 장점이 있다.

함수 선언식과 비교하여, 함수 표현식의 이점은 아래의 경우로 나뉜다.

  • 클로저
  • 인자 전달
  • IIFE

함수 표현식 장점

클로저

클로저(클로저 란?)는 함수가 종료돼도, 렉시컬 스코프의 index와 같은 정보를 유지한다.

function navsHandler(index) {
    return function navClickEvent(evt) {
        // 이벤트 코드
    }
}

var navs = document.querySelectorAll('.nav')
var i

for (i = 0; i < navs.length; i += 1) {
    navs[i].onclick = navsHandler(i)
}

이벤트 핸들러는 반복이 완료된 후 실행되므로, for 루프의 올바른 값을 유지하려면 클로저가 필요하다.

// 잘못된 예 1

var i

for (i = 0; i < list.length; i += 1) {
    document.querySelector('#item' + i).onclick = function doSomething(evt) {
        // i는 항상 list.length 값을 갖는다.
    }
}


// 잘못된 예 2

var list = document.querySelectorAll('.item')
var i
var doSomething = function (evt) {
       // 이 함수가 실행될 때까지 i의 값은 루프에 있던 값이 아니다.
    };

for (i = 0; i < list.length; i += 1) {
    item[i].onclick = doSomething;
}

여기서 해결책은 index를 인자로 외부 함수에 전달하여 해당 값을 내부 함수에 전달할 수 있도록하는 것이다. 일반적으로 내부 반환 함수에 필요한 정보를 구성하는 데 사용되는 핸들러 함수는 아래와 같다.

// 좋은 예

var list = ['item1', 'item2', 'item3']
var i
var doSomethingHandler = function (itemIndex) {
        return function doSomething(evt) {
            // 클로저가 생성되어, itemIndex를 인자로 참조 할 수 있게 된다.
            console.log(list[itemIndex]);
        };
    };

for (i = 0; i < list.length; i += 1) {
    list[i].onclick = doSomethingHandler(i);
}

인자 전달

함수 표현식은 중간 임시 변수에 할당 할 필요없이 함수에 직접 전달할 수 있다.

익명 함수의 형태로 jQuery에서 자주 볼 수 있다. 예를 들면 다음과 같다.

$(document).ready(function () {
    console.log('익명 함수');
});

forEach()와 같은 메서드는 함수 표현식이 배열 항목을 처리하는 데 사용된다. 해당 함수가 익명 함수일 필요는 없다. 함수가 수행해야하는 작업을 표현하고 디버깅을 돕기 위해 함수 표현식의 이름을 지정하는 것이 좋다.

var productIds = ['bisu', 'boxer', 'nada'];

productIds.forEach(function showProduct(productId) {
    ...
});

IIFE (즉시 주입 함수 표현식)

IIFE는 함수와 변수가 전역 스코프에 영향을 미치지 않도록 방지하는 데 사용된다. IIFE 내의 모든 속성은 익명 함수로 범위가 지정된다. 이는 코드가 다른 곳에서 부작용이 발생하지 않도록 방지하는 데 사용되는 일반적인 디자인 패턴이다.

또한 유지 관리하기 쉬운 섹션에 코드 블록을 포함하는 모듈 패턴으로도 사용된다. 그 예는 아래와 같다.

(function () {
    // 코드 ...
}());

모듈로 사용하면 코드를 쉽게 유지 관리 할 수 있다.

var myModule = (function () {
    var privateMethod = function () {
        console.log('A private method');
    },
    someMethod = function () {
        console.log('A public method');
    },
    anotherMethod = function () {
        console.log('Another public method');
    };

    return {
        someMethod: someMethod,
        anotherMethod: anotherMethod
    };
}());

결론

함수 표현식은 함수 선언식 보다 깔끔하고 가독성이 높은 코딩을 하게한다. 함수 표현식/선언식의 장단점 파악은 자바스크립트 디자인 패턴 공부에 있어서 필수로 알아야 하는 기초 단계일 것이다.

profile
Hi, I'm dean. Front-end developer who likes UI/UX Design.

0개의 댓글