본문 바로가기
📌 Front End/└ JavaScript

[JavaScript] 자바스크립트 함수 표현식 VS 함수 선언식

by 쫄리_ 2023. 3. 10.
728x90
반응형

함수 선언식이란?

변수 선언이 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
    };
}());

결론

함수 표현식은 함수 선언식 보다 깔끔하고 가독성이 높은 코딩을 하게한다.

함수 표현식/선언식의 장단점 파악은 자바스크립트 디자인 패턴 공부에 있어서 필수로 알아야 하는 기초 단계일 것이다

728x90
반응형