toggle-toggle / javascript-basic

🌱우아한 테크코스 프론트엔드 자바스크립트 기초 스터디 입니다.
9 stars 0 forks source link

[2021.03.11] IIFE, Module, Namespace #5

Closed ddongule closed 3 years ago

ddongule commented 3 years ago

IIFE(Immediately Invoked Function Expression)

들어가기 전에..

함수 선언식과 표현식 (맛보기)

즉시 실행 함수 표현에 대해 알아보려면 먼저 함수 선언식과 표현식에 대해 알아야한다. 아래와 같이 쓰는 것을 함수 선언식이라고 한다. 함수 선언식은 호이스팅에 영향을 받는다.

function 함수이름() {
  ...statements
}

아래와 같이 표현한 것을 함수 표현식이라고 한다. 함수 표현식은 호이스팅에 영향을 받지 않는다.

const 함수이름 = function() {
  ...statements
}

그럼.. IIFE란?

말 그대로 정의되자마자 즉시 실행되는 함수 이러한 즉시 실행 함수는 global Scope 를 오염시키지 않기 위해 사용 다양한 라이브러리들이 IIFE 패턴을 사용해 충돌을 방지하고 있다.

IIFE는 아래와 같이 작성할 수 있다. (1,2번이 자주 사용되고, 나머지는 그냥 알고만 있으면 된다.) 연산자를 사용한 방식은 return값이 있을 때 예상치 못한 결과가 나타날 수 있기 때문에 1,2방식이 더 널리 활용된다.

// 1.
(function() {
  ...statements
})();

// 2. 
(function () {
  ...statements
}());

// 3.
!function() {
  ...statements
})();

// 4.
+function() {
  ...statements
})();

// 5.
void function() {
  ...statements
})();

Javascript는 function 이라는 키워드를 볼 때마다, 함수의 정의가 일어날 것이라고 예측 하지만 앞에 +, -, ~, ! 등과 같은 1진 연산자들이 있으면 함수가 아닌 표현식으로 다룸 마지막 void는 함수를 식으로 다루어지게 강제하는 내용

IIFE는 결국 의 한 종류이기 때문에, 앞서 말했던 호이스팅이 발생하지 않는다. 아래와 같이 예시를 들 수 있다.

// 함수 선언식
boo(); // 실행된다.
function boo() {
    alert('booo!')
}

// 함수 표현식 
hoo(); // 실행되지 않는다.
var hoo = function () {
    alert('hooo!')
}

// 즉시 호출 함수 
(function mooyaho() {})();
alert(mooyaho()) // mooyaho not defined

즉시 실행 함수 표현의 장점

예시 1)

IIFE 사용 예제

// 예제 1.
const message = (function() {
    const secret = "I m scret!";
    return `The secret is ${secret.length} characters long.`
})();
console.log(message); //The secret is 10 characters long.

// 예제 2.
// 호출된 함수를 가지고 있는 변수 f
const f = (function() {
    let count = 0;
    return function() {
        return `i have been called ${++count} time(s).`
    }
})();

f(); // "i have been called 1 time(s)."
f(); // "i have been called 2 time(s)."

1의 예시에서 secret은 외부에서 접근할 수 없기 때문에 안전하게 보호된다. 2의 예시에서는 함수를 호출할 때마다 새로 연산되어 값이 리턴되는 것을 알 수 있다.


모듈이란?

개발하는 웹의 크기가 커지면 언젠가 파일을 여러개로 분리해야하는데, 이때 분리된 파일 각각을 "Module"이라고 부름 모듈에 export, import를 적용하면 다른 모듈을 불러와 함수를 호출할 수 있게 해준다.

// hi.js
export function sayHi(user) {
  alert(`hello, ${user}!`)
}
// main.js
import { sayHi } from "./hi.js"

alert(sayHi('John')) //alert가 뜸

모듈의 사용

모듈의 Scope

모듈은 단 한번만 평가됨

모듈은 단 한번만 실행되고, 실행된 모듈은 필요한 곳에 공유된다.

최상위 레벨의 this는 undefined

type="module"와 일반 스크립트의 다른 점

항상 지연 실행된다.

인라인 스크립트의 비동기 처리

구식 브라우저 대응

어플리케이션이나 라이브러리를 위해 전역 유효 범위에 많은 변수, 함수, 객체 등으로 어지럽히지 않도록 하기 위해 전역 객체를 하나만 만들고, 모든 기능을 이 객체에 추가하는 패턴 스크립트가 실행되는 환경을 항상 일정하게 만들어 관리하기 쉽게 만드는 일을 함 단순히 기능을 한데 묶기 위해 사용하는 객체를 네임스페이스라고 함

안티 패턴

// 생성자 함수 2개
function a() {}
function b() {}

// 변수 1개
var variable = 0;

// 객체 1개
var module_object = {};

좋은 패턴

var APP = {};

// 생성자
APP.a = function() {};
APP.b = function() {};

// 변수
APP.variable = 0;

// 객체
APP.module_object = {};

네임스페이스의 장점

프로그램이 복잡해지면서 코드의 각 부분들이 파일로 분리되어 문서에 포함되는 경우가 많은데, 그러다보면 이미 있는걸 덮어쓰는 경우가 있으니 아래 예시의 1번처럼 객체를 바로 선언하는게 아니라 2번처럼 MYAPP이 이미 선언되었는지 확인하고 정의해주어야 함(3번과 2번은 같음)

// 1번
var MYAPP = {};

// 2번
if (typeof MYAPP === "undefined") {
    var MYAPP = {};
}

// 3번
var MYAPP = MYAPP || {};

하지만 이런 코드의 문제는 Namespace의 깊이가 깊어질수록 단계별로 계속 확인해주어야 한다는 것 그래서 이렇게 이러한 작업을 맡을 함수를 미리 선언하고 전역 객체가 존재하는지 확인하고 만들어줄 수 있음

var MYAPP = MYAPP || {}; // MYAPP이 이미 선언되었는지 확인 후 객체생성
MYAPP.nsFunc = function (ns_string) {
    // '.'으로 구분된 네임스페이스 표기를 쪼갬
    var sections = ns_string.split('.'),
        parent = MYAPP,
        i;

    // 최상단의 MYAPP객체는 이미 선언되었으므로 제거
    if (sections[0] === "MYAPP") {
        sections = sections.slice(1);
    }

    var s_length = sections.length;
    for (i=0; i<s_length; i+=1) {
        // 프로퍼티가 존재하지 않아야만 생성
        if (typeof parent[sections[i]] === "undefined") {
            parent[sections[i]] = {};
        }
        parent = parent[sections[i]];
    }
    return parent;
};

사용은 아래와 같이 하면 됨

MYAPP.nsFunc('woowa.frontend.javascript.crew')
console.log(window.MYAPP)