치춘짱베리굿나이스
require, import, export 본문
다른 파일에서 함수 가져오기
작업을 하다 보면 한 파일에 함수가 매우매우매우매우… 많아져서 보기 싫어질 때가 많다
파일을 분리하고, 해당 파일에서 함수를 불러오는 식으로 작업하면 한 파일당 한두 개의 함수에 집중할 수 있기 때문에 코드가 깔끔해진다
프론트엔드 컴포넌트를 만들 때도 거의 무조건 (특정 컴포넌트 안에서만 사용되는 한두줄짜리 컴포넌트가 아닌 이상) 한 파일에 컴포넌트 1개 룰을 지키면서 코딩하다 보니 이제 각 파일별로 주제가 명확하지 않으면 코드 읽기가 어려운 지경에 왔다
다른 파일에서 모듈을 불러오는 방법은 크게 두 가지가 있는데, require
와 import
이다
사실 다른 게시글에서 적었지만 정보가 상당히 빈약해서.. 삭제 후 더 자료검색해서 새로 작성하였다
require
const React = require('react');
const { Component } = React;
node의 모듈 시스템으로 module.exports
로 내보낸 모듈을 다른 곳에서 쓰게 하는 문법
구조분해 방식으로 작성된 부분은 (위의 const {component}
) 내보낸 대상이 객체거나 배열일 때 사용가능하다
commonJS 문법이라 ES6 코드를 실행시킬 수 없는 환경에서는 require
를 쓸 수밖에 없다 ⇒ import로 완벽히 대체는 아직 불가능하다
let input = require("fs").readFileSync("/dev/stdin");
직접 내보낸 require
문에 대하여 메서드 체이닝으로 바로 다음 메서드를 실행시킬 수 있다
module.exports = {
foo,
bar,
dap
};
/* 불러올 때 */
let { foo } = require("./testFunc.js");
/* 다음과 같다 */
let { foo } = {
foo: () => console.log("foo"),
bar: () => console.log("bar"),
dap: () => console.log("dap")
};
require 함수는 해당 경로에서 module.exports
로 내보낸 객체를 바로 반환한다
따라서 module.exports
로 내보낸 객체를 그대로 require
함수 위치에 넣은 것과 똑같은 의미를 갖는다
나는 foo
만 쓰고 싶은데 foo
, bar
, dap
을 전부 불러온 꼴이 되어버렸다
이처럼 require
은 내보내기한 모든 코드들이 불러와지기 때문에 실제로 어느 코드가 사용되는지 명확히 알 수 없다
module.exports
module.exports = testFunc;
module.exports = {
foo,
bar,
dap
};
/* 사용할 때 */
const testFunc = require("./testFunc.js"); // 단일 함수 내보내기
const obj = require("./test.js"); // 여러 객체 내보내기
obj.foo();
/* 구조분해 */
const { foo, bar } = require("./test.js");
module.exports
문을 통해 객체 하나만을 반환하거나, 중괄호 ({}
) 로 묶어 여러 객체를 한번에 반환할 수 있다
exports.foo = foo;
exports.bar = bar;
/* 사용할 때 */
const obj = require("./test.js");
obj.foo();
/* 구조분해 */
const { foo, bar } = require("./test.js");
exports
만 사용해도 같은 방법으로 사용할 수 있다
exports
는 module.exports
의 참조값이라 (같은 값을 바라보고 있다는 뜻) 같은 방식으로 사용할 수 있다
export
가 module.exports
의 바로가기 (네임스페이스) 라고 생각하면 된다
다만 exports = foo
와 같이 바로 할당하는 방식은 동작하지 않고, exports
를 객체처럼 사용하여 프롭퍼티를 묶어주는 것만 가능하다
바로 할당하여 사용하면 exports
와 module.exports
의 참조관계를 끊어버리고 exports
라는 새로운 변수로 바뀌기 때문이라고 한다
import
import React, { Component } from 'react'
위의 require
문을 한 줄로 깔끔하게 작성한 것, 파일 최상단에 작성한다
require
문은 파일 중간에서도 호출할 수 있지만, import
문은 무조건 파일 상단에 위치해야 한다
from
뒤에는 파일의 경로, import
뒤에는 불러올 모듈명을 적어주면 되고, export
로 내보낸 모듈을 불러올 수 있다
ES6 (es2015) 전용 문법이기 때문에 ES6을 지원하지 않는 브라우저는 해당 구문이 오류가 발생해야 하지만, 바벨이 알아서 번역해서 컴파일링 해 준다 (짱)
단 ES6 모듈 문법이기 때문에 commonJS에서는 동작하지 않고, 따라서 파일 확장자가 .mjs
이거나 package.json
에 부가 설정을 해 주어야 한다
package.json에 설정하기
{
"type": "module"
}
위와 같이 type
속성을 module
로 지정해주면 해당 작업 레포지토리의 모든 파일을 모듈로 인식하여 import문을 쓸 수 있다
다르게 말하자면 type: commonJS
일 땐 이 구문을 사용할 수 없다
export
/* named export */
export const foo = () => { console.log("foo"); }
/* default export */
const foo = () => { console.log("foo"); }
export default foo;
module.exports
와 비슷한 역할을 하지만, import
문에 대응되는 내보내기 키워드이다
export default
는 Default Export라 하며, 한 파일에 기본값 하나만 내보내기 할 수 있고, (내보내기 한 값이 객체가 아니라면) 구조분해 할당으로 가져올 수 없다
export const
는 Named Export라 하며, 한 파일에 여러 개가 존재할 수 있다
import { default as foo } from "./test.js";
export default
로 내보내기하는 것은 사실상 default
라는 이름으로 Named Export하는 것과 같아서, 위와 같이 가져오기가 가능하다
require vs import
require
- 동적으로 가져오는 방식이기 때문에, 조건부로 모듈을 가져오는 등이 가능하다
- 파일의 어디서든 필요한 모듈을 불러올 수 있다
- 해당 파일의 모든 내보내기를 한번에 가져오기 때문에, 메모리가 더 많이 소모된다
import
- 정적으로 가져오는 방식이기 때문에, 조건부 호출이 불가능하다
- async / await을 사용하여 동적으로 가져오는 것이 가능하다
- 파일 최상단에서만 모듈을 불러오는 것이 가능하다
- 사용하려는 모듈만 선택적으로 가져오기 때문에, 성능이 더 좋고 메모리가 절약된다 (트리쉐이킹)
- 이 이점 때문에 정적으로 동작하고, 파일 최상단에서만 불러오도록 고정되어 있다
.mjs
확장자 (ES6 module 타입) 또는package.json
에type: module
로 명시되어 있을 경우에만 사용가능하다
참고자료
자바스크립트 ES6 모듈 내보내기/불러오기 (import)
NODE JS - 모듈이란? , module.export 와 exports의 차이
require(), exports, module.exports 공식문서로 이해하기
module.exports와 exports 차이 이해하기
export const
vs. export default
in ES6
'Javascript + Typescript > 이론과 문법' 카테고리의 다른 글
자바스크립트에서의 객체지향 (1) 객체지향 기본 (0) | 2022.07.26 |
---|---|
자바스크립트의 대부분 요소는 객체인가요? (0) | 2022.07.26 |
Throttle & Debounce (0) | 2022.05.18 |
비동기 처리와 Promise (0) | 2022.05.13 |
[Typescript] Type vs Interface (0) | 2022.05.09 |