🚩 모듈은 재사용 가능한 코드 조각을 캡슐화하고 기본
🚩자바스크립트 파일에서 쉽게 재사용할 수 있게 해줍니다.
캡슐화 한다는 것은 무엇일까요?
자바스크립트 모듈은 관련된 함수, 변수, 객체, 클래스 등을 하나의 파일로 그룹화하고,
이를 모듈이라고 합니다.
이렇게 그룹화를 하게 되면 기능적으로 연관된 코드들을 묶어 관리할 수 있으며,
모듈 외부에서는 내부 구현을 알 필요 없이 제공되는 API
를 통해
모듈을 사용할 수 있다.
캡슐 안에 정보와 로직을 넣어 보관한다고 이해하시는 것이 좋다.
모듈이란 무엇일까?
ES6
에서는 export
키워드를 사용하여 모듈을 만들고,
다른 파일에서 사용할 수 있게 합니다.
모듈은 재사용할 수 있는 함수, 객체 또는 원시 값을 의미합니다.
🚩 기억해야 하는 내용들
Node
환경이 존재합니다.Node
환경에서의 모듈 import
방식은 CommonJS
방식과 ES6
방식이 있어요.React
개발 환경은 대부분 ES6
에서 제시한 방법을 사용합니다.여기서 CommonJS
의 방식이란?
CommonJS
는 주로 서버 사이드에서 사용을 합니다.
Node.js
의 기본 모듈 시스템이고 다음과 같은 특징을 가집니다.
1. 동기적 로딩
CommonJS
모듈은 파일이 로컬 디스크에 있기 때문에 동기적으로 로딩됩니다.
이는 서버 환경에서는 문제가 되지 않지만,
브라우저 환경에서는 네트워크 지연으로 인해 문제가 될 수 있다.
2. 단일 객체 내보내기
모듈은 module.exports
객체를 통해 전체 모듈을 하나의 객체로 내보내며,
이 객체를 요구하는 다른 모듈은 require()
함수를 사용하여 가져옵니다.
예시로 아래 코드의 math.js
는 두 함수를 객체로 내보내고,
app.js
는 이 모듈을 require
함수를 사용하여 불러와 함수를 사용합니다.
// libs/math.js
module.exports = {
add: function(x, y) {
return x + y;
},
subtract: function(x, y) {
return x - y;
}
};
// app.js
const math = require('./libs/math');
console.log(math.add(2, 3)); // 5
// math.js
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;
export const ONE = 1;
export const sample = {
one: 1,
two: 2
}
import
구문을 사용하여 파일에서 함수를 불러와 사용할 수 있습니다.
// app.js
import { add, multiply, ONE, sample } from './math.js';
console.log(add(2, 3)); //5
console.log(multiply(2, 3)); //6
console.log(ONE); //1
console.log(sample.two); //2
🚩 명확한 종속성 관리
전통적으로 script 태그
를 사용하여 자바스크립트 파일을 로드하는 방식은
스크립트 파일간의 종속성과 로딩 순서를 수동으로 관리해야 했습니다.
이 방식은 프로젝트의 규모가 커질수록 종속성을 추적하고 관리하기 어려워지며,
실수로 인한 버그 발생 가능성을 높입니다.
<!-- 전통적인 스크립트 로딩 방식 -->
<script src="jquery.js"></script>
<script src="plugin.js"></script> <!-- 이 스크립트는 jquery.js에 의존 -->
<script src="app.js"></script> <!-- 이 스크립트는 plugin.js와 jquery.js에 의존 -->
모듈 시스템을 사용하면 각 모 듈이 필요로 하는 종속성을 내부적으로 선언하므로,
개발자는 파일을 로드하는 순서에 신경 쓸 필요가 없습니다.
모듈 로더(ex) Webpack, Rollup)
가 이러한 종속성을 해석하고 올바른 순서로 스크립트를 묶어줍니다.
// ES6 모듈 사용 예시
import $ from 'jquery';
import plugin from 'plugin'; // 자동으로 jQuery에 대한 의존성을 처리
import app from 'app'; // 모든 의존성이 충족되면 실행
🚩 코드 캡슐화의 충돌 방지
모듈은 자체적인 스코프를 가지므로, 모듈 외부에서는 모듈 내부의 변수에 직접 접근할 수 없습니다.
따라서 전역 변수의 오염을 방지할 수 있고, 이름이 서로 충돌하는 것을 막아준다.
예시로 여러 스크립트에서 동일한 함수이름을 사용하더라도 모듈을 사용하면
각 스크립트에서 정의된 함수는 해당 모듈 내에서만 유효하다.
// module1.js
export function conflictFunction() {
console.log('Module 1의 함수');
}
// module2.js
export function conflictFunction() {
console.log('Module 2의 함수');
}
// app.js
import { conflictFunction as function1 } from './module1';
import { conflictFunction as function2 } from './module2';
function1(); // "Module 1의 함수"
function2(); // "Module 2의 함수"
🚩 효율적인 코드 로딩
모듈 시스템을 통해 필요한 기능만을 선택적으로 불러올 수 있으며,
이는 애플리케이션의 초기 로딩 시간을 단축시킵니다.
코드 스플리팅을 사용하면 사용자의 현재 요구에 따라 필요한 코드만으로 동적으로 로드할 수 있습니다.
이러한 지연 로딩은 특히 대규모 애플리케이션에서 성능과 자원 사용을 최적화하는데 매우 효과적입니다.
// 동적으로 모듈 로드하기 (예: 사용자가 특정 기능을 활성화했을 때)
button.addEventListener('click', event => {
import('./heavyModule.js')
.then(module => {
module.heavyFunction();
})
.catch(err => {
console.error("모듈 로딩에 실패했습니다.", err);
});
});
🚩 별칭 사용
import
시 특정 요소에 별칭을 지정하여 충돌을 방지하거나 명확성을 높일 수 있다.
import { square as sqr } from './utils.js';
console.log(sqr(4)); // 16
🚩 기본 내보내기와 가져오기
한 모듈에서 하나으 기본 값을 내보내고 이를 쉽게 가져올 수 있습니다.
모듈당 하나의 주요 기능을 내보낼 때 유용합니다.
export default
를 통해 내보내진 모듈은 import
시 이름변경이 가능합니다.
특정 경로에서 가져온 import
값은 하나밖에 존재하지 않기 때문에
이름을 명시하지 않아도 특정할 수 있다.
// math.js
export default function multiply(x, y) {
return x * y;
}
// app.js
import multiply from './math.js';
console.log(multiply(6, 7)); // 42
// export default 시 모듈이름 변경은 자유인걸 확인할 수 있다.
// utils.js
export default function square(x) {
return x * x;
}
// main.js
import mySquare from './utils.js';
console.log(mySquare(4)); // 출력: 16
모듈의 모든 내보내기를 한 번에 가져올 때 사용하는 방식이다.
// app.js
import * as MathFunctions from './math.js';
console.log(MathFunctions.add(10, 5)); // 15
console.log(MathFunctions.multiply(10, 5)); // 50