require
는 Node JS에서 사용되고 있는 CommonJS 키워드이고, 여기서 배워볼 import
는 ES6에서 새롭게 도입된 키워드입니다. 두 개의 키워드 모두 하나의 파일에서 다른 파일의 코드를 불러온다는 동일한 목적을 가지고 있습니다.
const moment = require("moment")
import moment from "moment"
위 2줄의 코드는 기본적으로 MomentJS
라는 라이브러리를 불러오는 동일한 작업을 수행하고 있습니다. CommonJS 방식을 따른 첫번째 코드는 require
키워드를 사용하여 여터 다른 변수를 할당하듯이 모듈을 불러오는 반면에 ES6 방식을 따른 두번째 코드는 Java나 Python 처럼 import
키워드를 사용하여 좀 더 명시적으로 모듈을 불러오고 있습니다.
require()
함수 사용법에 대해선 위에 작성되어 있으니 ES6기반 import/export 방법에 대해서 알아보겠습니다.
먼저 ES6 모듈 시스템은 CommonJS 모듈 시스템보다 최신 스펙이다 보니 여러가지 이점이 많습니다.
우선 import
, from
, export
, default
처럼 모듈 관리 전용 키워드를 사용합니다. 그렇기 떄문에 가독성 측면에서 유리한 점이 많습니다. 또한 비동기 방식으로 작동하고 모듈에서 실제로 쓰이는 부분만 불러오기 때문에 성능과 메모리 부분에사도 유리한 측면이 있습니다.
앞으로 설명드릴 Named Prameter
와 같이 CommonJS에서는 지원하지 않는 기능들이 있습니다.
먼저 하나의 자바스크립트 모듈 파일에서 여러 개의 객체를 내보내고 불러오는 방법을 알아보도록 하겠습니다.
CommonJS에서는 내보낼 복수 객체들을 exports
변수의 속성으로 할당하는 방식을 썼었는데, ES6에서는 import
키워드의 짝꿍인 export
키워드를 사용해서 명시적으로 선언해 줍니다. 이 때 내보내는 변수나 함수의 이름이 그대로 불러낼 때 사용하게 되는 이름이 되기 때문에 이를 Named Exports라고 일컫습니다.
아래는 미국과 캐나다 달러를 상호 변환해주는 자바스크립트 예제 코드입니다. 이 파일에는 3개의 함수가 있는데 아래 2개의 함수만 다른 파일에서 접근할 수 있도록 내보내기를 하였습니다. 첫번째 방법처럼 선언과 동시에 내보낼 수도 있고, 두번째 방법처럼 선언 후에 별도로 내보낼 수도 있습니다.
currency-functions.js
const exchangeRate = 0.91;
// 내보내지 않음
function roundTwoDecimals(amount) {
return Math.round(amount * 100) / 100;
}
// 첫번째 내보내기 방법
export function canadianToUs(canadian) {
return roundTwoDecimals(canadian * exchangeRate);
}
// 두번째 내보내기 방법
const usToCanadian = function(us) {
return roundTwoDecimals(us / exchangeRate)
}
export { usToCanadian }
여러 객체(Named Exports)를 불러올 때는 ES6의 Destructuring
(구조 분해 할당) 문법을 사용해서 필요한 객체만 선택적으로 전역에서 사용하거나, 모든 객체에 별명을 붙이고 그 별명을 통해서 접근할 수도 있습니다.
test-currency-function.js
// Desturturing
import { canadianToUs } from "./currency-functions"
console.log("50 Canadian dollars equals this amount of US dollars:");
console.log(canadianToUs(50));
// Alias
import * as currency from "./currency-functions"
console.log("30 US dollars equals this amount of Canadian dollars:");
console.log(currency.usToCanadian(30));
실행 결과
50 Canadian dollars equals this amount of US dollars:
45.5
30 US dollars equals this amount of Canadian dollars:
32.97
다음으로 하나의 자바스크립트 모듈 파일에서 단 하나의 객체를 내보내고 불러오는 방법을 알아보겠습니다.
CommonJS에서는 내보낼 단일 객체를 module.exports
변수에 할당하는 방식을 썼었는데, ES6에서는 그 대신 export default
키워드를 사용해서 명시적으로 선언해줍니다. 하나의 모듈에서 하나의 객체만 내보내기 때문에 이를 Default Export라고 부릅니다.
아래 예제는 두개 함수를 객체로 묶어서 내보내기를 한 코드입니다. 이름이 필요없기 때문에 별도 변수 할당 없이 바로 객체를 내보내기 할 수 있습니다. 내보낼때 어떤 이름도 지정하지 않기 때문에 불러올 때도 아무 이름이나 사용할 수 있습니다.
currency-object.js
const exchangeRate = 0.91;
// 내보내지 않음
function roundTWoDecimals(amount) {
return Math.round(amount * 100) / 100;
}
// 내보내기
export default {
canadianToUs(canadian){
return roundTwoDecimals(canadian * exchangeRate);
},
usToCanadian: function(us){
return roundTwoDecimals(us / exhangeRate);
},
}
변수에 할당을 하여 내보내기를 하고 싶다면 다음과 같이 작성할 수도 있습니다.
const obj = {
canadianToUs(canadian) {
return roundTwoDecimals(canadian * exchangeRate)
},
}
obj.usToCanadian = function (us) {
return roundTwoDecimals(us / exchangeRate)
}
export default obj
하나의 객체(Default Export)를 불러올 때는 간단하게 import
키워드를 사용해서 아무 이름이나 원하는 이름을 주고 해당 객체를 통해 속성에 접근하면 됩니다.
test-currency-object.js
import currency from "./currency-object"
console.log("50 Canadian dollars equals this amount of US dollars:")
console.log(currency.canadianToUs(50))
console.log("30 US dollars equals this amount of Canadian dollars:")
console.log(currency.usToCanadian(30))
실행 결과
50 Canadian dollars equals this amount of US dollars:
45.5
30 US dollars equals this amount of Canadian dollars:
32.97
한가지 주의해야 할 점은 Bable없이 순수하게 Node.js 최신 버전으로 ES모듈을 시용하는 거라면 import를 살용할 떄 .js 확장자를 붙여주어야 합니다.
require()
가 있는데 import
가 왜 생겼을까요?require
와 import
에 대해서 비교해 보기 위해서는 우선 CommonJS
와 AMD(Asynchronous Module Definition)
, ES6
내장모듈과 같은 자바스크립트의 모듈 시스템에 대해 알고 있어야 합니다.
기존의 자바스크립트(ES5, 현재 대부분의 브라우저에서 지원하는 자바스크립트 문법)는 모듈이라는 개념이 부족하여 각 모듈(또는 파일) 간의 의존성 처리에 제한이 있었습니다. 고전적인 웹 프로젝트에서 자바스크립트를 사용하는 방법을 살펴보면, HTML 파일 내부에 <script>
태그를 삽입하여 모듈을 로드하고 있습니다. 하지만 이런 방식은 한가지 문제가 있는데, 자바스크립트 파일끼리 서로 모듈을 공유하는데 제약이 없다는 점입니다. 그 이유는 script
태그로 로드된 모듈은 모두 window
객체의 속성이기 때문에 서로 다른 파일에 위치하면서도 모든 객체를 공유할 수 있기 때문입니다.
이처럼 각 자바스크립트 파일이 독립적으로 존재하지 못해 발생하는 여러 문제들 (예를들어 다른 파일에서 같은 이름의 변수를 사용하는 경우) 때문에 하나의 모듈로 관리하기 위한 다양한 패턴(Module Pattern, 즉시 실행 함수 등)을 사용하여 의존성을 관리할 수 밖에 없었습니다.
이를 해결하기 위한 수단으로 모듈이라는 개념을 도입하여 정의한 방법(또는 표준)이 CommonJs 와 AMD 입니다. 이 둘은 내부적으로 모듈 서로 간의 의존성이 지원되지 않는 상태로 만들어 졌는데, ES6에 이르러 언어 내부적으로 자바스크립트 모듈 의존성을 지원하게 되었습니다. (import, export).
ES6 모듈은 기본적으로 CommonJs와 AMD 모듈을 혼용해서 사용할 수 있습니다. 모듈을 가져오는 부분에 require
와 import
를 같이 쓰더라도 문제없이 동작합니다.
import
는 ES6 문법이라 현재 사용되는 브라우저에서는 지원하지 않지만, bable과 같은 트랜스파일러가 해결해줄 수 있습니다. AMD는 생략하고 ES6와 CommonJS를 비교하여 설명해보겠습니다.
import
는 필요한 부분만 선택적으로 가져올 수 있고, 그것은 곧 메모리 성능의 최적화로 이루어 질 수 있습니다. 또한 비동기적으로 수행될 수 있어 조금 더 좋은 성능을 발휘할 수 있습니다.
또한 Require
모듈 시스템은 표준에 근거된 문법이 아닙니다. 현재 ES6
모듈이 존재하기 때문에 표준이 될 가능성은 거의 없습니다.
향후 다양한 구현에서 ES6
모듈을 기본적으로 지원하여 성능 면에서 유리 할 것입니다.
잘 읽었습니다! 👍