본문 바로가기

Javascript

[JavaScript] 모듈, module

반응형

 

일반적으로 자바스크립트의 패턴을 모아둔 것을 모듈(module)이라고 부른다.

가장 흔한 모듈 패턴 구현 방법은 모듈 노출(Revealing Module)이고, 아래의 예시는 이것의 변형이다.

 

예시 )

function module() {
    var something = "cool";
    var another = [1, 2, 3];

    function doSomething() {
        console.log(something);
    }

    function doAnoter() {
        console.log(another.join(" | "));
    }

    return {
        doSomething: doSomething,
        doAnother: doAnoter
    };
}

var test = module();

test.doSomething(); // cool
test.doAnother(); // 1 | 2 | 3

 

위 코드를 잠시 살펴보자.

 

1 ) module() 은 그저 하나의 함수일 뿐이지만, 모듈 인스턴스를 생성하려면 반드시 호출해야 한다.

     최외곽 함수가 실행되지 않으면 내부 스코프와 클로저는 생성되지 않는다.

 

2 ) module() 은 객체를 반환하고, 반환되는객체는 객체-리터럴 문법 {key:value, ...}에 따라 표기한다.

     해당 객체는 내장 함수들에 대한 참조를 가지지만, 내장 데이터 변수에대한 참조는 가지지 않는다.

     내장 데이터 변수는 비공개로 숨겨져 이 객체의 반환 값은 본질적으로 모듈의 공개 API라고 생각할 수 있다.

     객체의 반환 값은 최종적으로 외부 변수 test에 대입되고, test.doSomething() 과 같은 방식으로 API의 속성 메서드에 접근할 수 있다.

모듈에서 꼭 실제 객체(리터럴)을 반활할 필요 없이 직접 내부 함수를 반환해도 된다.
제이쿼리가 이런 반환을 하는 좋은 사례로, 제이쿼리와 $ 확인자는 제이쿼리 '모듈'의 공개 API고 동시에 그 자신들은 단순한 함수이기도 하다.

3 ) doSomething() 과 doAnother()은 모듈 인스턴스의 내부 스코프에 포함하는 클로저를 가진다.

     반환된 객체에 대한 속성 참조 방식으로 이 함수들을 해당 렉시컬 스코프 밖으로 옮길때 클로저를 확인하고 이용할 수 있는 조건이 있다.

     

     즉, 이 모듈 패턴을사용하려면 두 가지 조건이 있다.

     3-1 ) 하나의 최외곽 함수가 존재하고, 이 함수가 최소 한 번은 호출되어야 한다.

              호출할 때마다 새로운 모듈 인스턴스가 생성된다.

     3-2 ) 최외곽 함수는 최소 한 번은 하나의 내부 함수를 반환해야 한다.

              그래야 해당 내부 함수가 비공개 스코프에 대한 클로저를 가져 비공개 상태에 접근하고 수정할 수 있다.

하나의 함수 속성만을 가지는 객체는 진정한 모듈이 아니다.
함수 실행결과로 반환된 객체에 데이터 속성들이 있지만 닫힌 함수가 없다면 그 객체는 진정한 모듈이 아니다.

'싱글톤'만 생성하는 모듈 예시 )

var test = (function module() {
    var something = "cool";
    var another = [1, 2, 3];

    function doSomething() {
        console.log(something);
    }

    function doAnoter() {
        console.log(another.join(" | "));
    }

    return {
        doSomething: doSomething,
        doAnother: doAnoter
    };
})();

test.doSomething(); // cool
test.doAnother(); // 1 | 2 | 3

 

위 코드는 모듈 함수를 IIFE로 바꾸고, 즉시 실행시켜 반환 값을 직접 하나의 모듈 인스턴스 확인자 test에 대입시켰다.

 

인자를 받고 있는 모듈 예시 )

function module(msg) {
    function doSomething() {
        console.log(msg);
    }

    return {
        doSomething: doSomething
    };
}

var test = module("Hello, JS !!");
test.doSomething(); // Hello, JS !!

 

위 코드는 모듈은 함수이므로 인자를 받을 수 있어 공개 API로 반환하는 객체에 이름을 정하는 방식을 보여줬다.

 


ES6 부터는 모듈 개념을 지원하는 문법이 추가되었다.

모듈 시스템을 불러올 때 ES6은 파일을 개별 모듈로 처리한다.

각 모듈은 다른 모듈 또는 특정 API 멤버를 불러오거나 자신의 공개 API 멤버를 내보낼 수도 있다.

 

함수 기반 모듈은 정적으로 알려진, 컴파일러가 읽을 수 있는 패턴이 아니다.
따라서 이들 API는 런타임 전까지 해석되지 않고, 실제로 모듈 API를 런타임에 수정할 수 있다는 것이다.

반면, ES6 모듈 API는 정적이라서 런타임에 변하지 않는다.
따라서 컴파일러는 컴파일레이션 중에 불러온 모듈 API 멤버 참조가 실제로 존재하는 지 확인 할 수 있어
참조가 존재하지 않으면, 컴파일리시 초기 오류를 발생시켜 전통적인 변수 참조를 위한 동적 런타임까지 기다리지 않는다.

ES6 모듈은 inline 형식을 지원하지 않고, 반드시 개별 파일(모듈당 파일 하나)에 정의되어야 한다.

브라우저와 엔진은 기본 모듈 로더를 가지고, 모듈을 불러올 때 모듈 로더는 동기적으로 모듈 파일을 불러온다.

 

예시 )

// bar.js
function hello(who) {
    return "Let me introduce: " + who;
}

export hello;

// foo.js
import hello from "bar";

var hungry = "Gosimi";
function awesome() {
    console.log(hello(hungry).toUpperCase();
};

export awesome;

// test.js
module foo from "foo";
module bar from "bar";

console.log(
    bar.hello("chati"); // Let me introduce: Gosimi
);
foo.awsome(); // LET ME INTRODUCE: GOSIMI

 

키워드 export 는 변수와 함수 확인자를 현재 모듈의 공개 API로 내보내고, 이 연산자들은 모듈의 정의에 따라 필요하면 사용할 수 있다.

키워드 import 는 모듈 API에서 하나 이상의 멤버를 불러와 특정 변수(예시에서는 hello)에 묶어 현재 스코프에 저장한다.

키워드 module 은 모듈 API 전체를 불러와 특정 변수(예시에서는 foo, bar)에 묶는다.

앞서 살펴본 함수-클로저 모듈처럼 모듈 파일의 내용은 스코프 클로저에 감싸진 것으로 처리된다.

 


[JavaScript] 스코프, Scope : chati.tistory.com/157

 

[JavaScript] 스코프, Scope

⌗ 스코프, Scope 특정 상소에 변수를 저장하고 나중에 그 변수를 찾는데는 잘 정의된 규칙이 필요하는데 이를 스코프(Scope)라고 한다. 변수를 검색하는 이유는 변수에 값을 대입(LHS 참조)하거나

chati.tistory.com

 

[JavaScript] 스코프 클로저, Scope Closure : chati.tistory.com/175

 

[JavaScript] 스코프 클로저, Scope Closure

클로저는 새롭게 문법과 패턴을 배워야할 특별한 도구가 아닌 그저 인식하고 받아들이면된다. 이는 자바스크립트의 모든 곳에 존재하며, 렉시컬 스코프에 의존해 코드를 작성한 결과로 그냥 발

chati.tistory.com

 


[참고] You Don't Know JS 타입과 문법, 스코프와 클로저 - 카일 심슨

 

반응형

❥ CHATI Github