1. 모듈의 개념, 등장 이유
모듈은 프로그램을 구성하는 구성요소의 일부를 말한다.
쉽게 말하자면 큰 애플리케이션을 작게 파일로 분리해서 관리할때 이 파일 각각을 말한다.
보통 클래스 하나 + 특정한 목적을 가지는 복수의 함수로 구성된 라이브러리 하나 정도로 구성.
JS에서 모듈의 등장
스크립트의 크기가 점차 커지고 기능이 복잡해지자 자바스크립트 커뮤니티는 라이브러리를 만들어서 필요한 모듈을 언제든지 불러올 수 있도록 하거나 모듈로 쉽게 분리 할 수 있는 방법들을 제시했다.
대표적으로 AMD, CommonJS, UMD 와 같은 모듈 시스템이 있다.
•
AMD : 가장 오래된 모듈 시스템 중 하나. require.js라는 라이브러리를 통해 처음 개발.
•
CommonJS : Node.js 서버를 위해 만들어짐
•
UMD : AMD와 CommonJS와 같은 모듈 시스템을 함께 사용하기 위해 등장
위의 모든 모듈 시스템은 2015의 JS 표준으로 등재가 되었고, 대부분의 브라우저와 Node.js가 모듈 시스템을 지원한다.
CommonJS
서버사이드 및 데스크탑 어플리케이션에서 JS를 지원하기 위해서 탄생함.
다른 모듈을 사용할때 require을, 모듈을 해당 스코프 밖으로 보낼 때에는 module.exports를 사용한다.
→ node.js에서 사용한다.
•
a.js 파일
const printHelloWorld = () => {
console.log('Hello Wolrd');
};
module.exports = {
printHelloWorld
};
JavaScript
복사
•
b.js
const func = require('./a.js'); // 같은 디렉토리에 있다고 가정
func.printHelloWorld();
JavaScript
복사
여기서 module.exports는 현재 모듈에 대한 정보를 갖고 있는 객체이다.
id, path, parent 등의 속성이 있고 exports 객체를 가짐.
•
module.exports 대신에 exports를 사용할 수도 있음
exports.printHelloWorld = printHelloWorld;
JavaScript
복사
→ exports 의 속성으로 넣는 방법은 module.exports를 참조해서 사용하므로 직접 module.exports를 수정하지 않고 객체의 멤버를 만들어서 수정하는 방식을 사용한다.
두가지 방법의 차이점
코드를 살펴볼때 두가지 방법의 차이가 드러난다.
•
module.exports={} 사용하는 방법
function add(a, b) {
return a + b;
}
function substract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
return a / b;
}
module.exports = {
add: add,
substract: substract,
multiply: multiply,
divide: divide,
};
JavaScript
복사
→ 여러개의 함수를 한번에 넣기에 용이하다.
•
exports 의 속성을 사용하는 방법
exports.add = function(a, b) {
return a + b;
};
exports.substract = function(a, b) {
return a - b;
};
exports.multiply = function(a, b) {
return a * b;
};
exports.divide = function(a, b) {
return a / b;
};
JavaScript
복사
→ 하나하나씩 따로 추가하는 느낌이 강하다.
주의!!! exports = divide;이렇게 넣지 않도록 주의하자
exports 가 module.exports를 참조하고 있기 때문이다.
→ 여러개의 객체를 따로 export 할때 사용한다.
AMD(Asynchoronous Module Definition)
비동기 모듈에 대한 표준안을 다룬다.
CommonJS가 서버쪽에서 장점이 많은 반면 AMD는 브라우저 쪽에서 더 장점이 많다.
UMD (Universal Module Definition)
위 두개의 모듈을 통합하기 위한 하나의 패턴
ES6 방식
import와 export 구문을 사용하는 방식이다.
EXPORT시에 named export를 사용하는 경우와 default export 를 사용하는 경우로 나뉘어진다.
•
named export
→ {} 로 묶어서 가져와야 한다.
export const B = () => {};
import {B} from 'moduleB';
JavaScript
복사
•
default export
→ 그대로 사용가능
export A = () => {};
export default A;
import A from 'moduleA';
JavaScript
복사
2. 모듈의 사용과 특징
그래서 모듈을 어떻게 사용한다고?
모듈은 export 와 import 와 같은 지시자를 통해서 다를 모듈을 불러와서 불러온 모듈에 있는 함수들을 호출할 수 있는 등의 기능 공유가 가능하게 된다.
•
export : 외부 모듈 에서 해당 변수나 함수에 접근할 수 있게!
•
import : 외부 모듈의 기능을 가져와서 쓸 수 있음
모듈의 특징
•
모듈은 특수한 키워드나 기능과 함께 사용이 되므로 우선 <script type=”module”> 과 같은 속성을 설정해서 해당 스크립트가 모듈인것을 알 수 있도록 해줘야 한다.
•
모듈은 로컬 파일에서 동작하지 않고, http 또는 https 프로토콜을 통해서만 동작한다.
스크립트와 다른점
•
스크립트와 다르게 ‘use strict’ 엄격한 모드로 실행이 된다.
•
모듈 내부에서 정의한 변수나 함수는 다른 스크립트에서 접근할 수 없다.
→ export 와 import를 꼭 사용해야 한다.
•
동일한 모듈이 여러곳에서 사용되더라도 모듈은 최초 호출시 단 한번만 실행된다.
→ 앞서 특정 모듈에서 불러온 모듈을 수정하게 되면 다른 모듈에서 특정 모듈의 수정된 결과가 적용된다.
// 📁 1.js
import {admin} from './admin.js';
admin.name = "Pete"; //John -> Pete
// 📁 2.js
import {admin} from './admin.js';
alert(admin.name); // Pete
JavaScript
복사
이를 이용하면 모듈 설정을 쉽게 할 수 있음
◦
다음과 같은 모듈이 있다고 해보자.
// 📁 admin.js
export let admin = { };
export function sayHi() {
alert(`${admin.name}님, 안녕하세요!`);
}
JavaScript
복사
◦
최초 사용 위치에서 다음과 같이 설정한 경우
// 📁 init.js
import {admin} from './admin.js';
admin.name = "유림";
JavaScript
복사
◦
다른곳에서 호출시 사용이 가능하다.
// 📁 other.js
import {admin, sayHi} from './admin.js';
alert(admin.name); // 유림
sayHi(); // 유림님, 안녕하세요!
JavaScript
복사
•
import.meta 객체를 통해 현재 모듈에 대한 정보를 가져올 수 있다.
ex) import.meta.url : 현재 모듈이 위치한 html 페이지의 url
•
this 는 undefined 이다.
<script>
alert(this); // window
</script>
<script type="module">
alert(this); // undefined
</script>
JavaScript
복사
브라우저 환경에서 모듈이 스크립트와 다른점
•
항상 지연 실행된다.
→ html 처리와 외부 모듈 스크립트는 병렬적으로 불러와진다.
모듈은 html 문서가 준비될 때까지 대기 상태였다가 HTML 문서가 만들어진 이후에 실행된다.
→ 따라서 항상 모듈 스크립트는 완전한 html 페이지를 보고 요소에 접근할 수 있다.
•
인라인 스크립트에서도 ‘async’ 속성을 사용할 수 있다
async : 로딩이 끝나면 다른 스크립트나 html 문서가 처리되길 기다리지 않고 실행되도록 함.
그냥 스크립트는 인라인 스크립트로 작성시 async 로 진행할 수 없다.
•
경로가 없는 모듈은 금지된다(브라우저가 읽을 수 없다)
import {sayHi} from 'sayHi'; // Error!
import {sayHi} from './sayHi.js'; // Correct!
JavaScript
복사