24-25/Node.js 1
[노드 1팀] 3장. 노드 기능 알아보기 (1)
gooroominuna
2024. 10. 11. 10:03
728x90
3.1. REPL 사용하기
REPL(Read Eval Print Loop)
- REPL은 노드에서 제공하는 콘솔이다.
- 입력한 코드를 읽고(Read), 해석하여(Eval), 결과를 출력하고(Print),
종료할 때까지 반복(Loop)한다. - REPL을 이용하면 JavaScript 코드를 미리 컴파일하지 않고, 바로 실행할 수 있다.
REPL 사용법
- 콘솔 (Windows의 cmd, Mac/Linux/VS Code의 터미널)을 열고 node를 입력한다.
- > 모양이 나오면 JavaScript 코드를 입력할 수 있다.
- Ctrl + C를 두 번 누르거나 .exit을 입력하여 REPL을 종료할 수 있다.
3.2. JS 파일 실행하기
- 긴 코드를 실행할 때는 REPL 대신,
코드를 자바스크립트 파일로 만든 후 한 번에 실행하는 것이 편리하다. - 파일을 생성한 후, 콘솔에서 node [파일 경로]를 입력하여 실행한다.
- 이때 확장자(.js)는 생략 가능하다.
3.3. 모듈로 만들기
Module (모듈)
① 모듈
- 모듈은 특정한 기능을 하는 함수나 변수들의 집합이다.
- 여러 파일에서 재사용되는 함수나 변수를 모듈로 만들어두면 편리하다.
② 노드는 코드를 모듈로 만들 수 있다.
- 보통 파일 하나가 모듈 하나가 되며,
노드에서는 대부분의 파일이 다른 파일을 모듈로 사용한다. - 노드에서는 CommonJS와 ECMAScript, 두 가지 형식의 모듈을 사용한다.
CommonJS
① CommonJS 모듈
- 표준 자바스크립트 모듈이 나오기 이전부터 쓰였던 것으로, 가장 널리 쓰이는 모듈이다.
② CommonJS 형식으로 모듈 만들기
- module.exports에 객체나 함수, 변수를 대입하면, 이 파일은 모듈로서 기능한다.
var.js
const odd = 'CJS 홀수입니다'; const even = 'CJS 짝수입니다'; module.exports = { odd, even, };
다른 파일에서 var.js 파일을 불러오면 module.exports에 대입된 값을 사용할 수 있다. - require 함수로 모듈을 불러올 수 있다.
func.js
const { odd, even } = require('./var'); function checkOddOrEven(num) { if (num % 2) { return odd; } return even; } module.exports = checkOddOrEven;
require 함수 안에 불러올 모듈의 경로를 적는다. 이때 확장자와 index.js는 생략 가능하다.
require 함수를 통해 var.js의 module.exports에 담겨 있던 객체를 불러와 func.js에서 사용할 수 있게 된다.
** require가 반드시 파일 최상단에, module.exports가 최하단에 위치할 필요가 없다.
** require 함수는 require.cache와 require.main 속성을 갖는다.
한번 require 한 파일은 require.cache에 저장되어 재사용할 수 있고,
require.main은 노드 실행 시 첫 모듈을 가리킨다. - 모듈 하나가 여러 개의 모듈을 사용할 수 있고,
모듈 하나가 여러 개의 모듈에 사용될 수도 있다.
index.js
const { odd, even } = require('./var'); const checkNumber = require('./func'); function checkStringOddOrEven(str) { if (str.length % 2) { // 홀수이면 return odd; } return even; } console.log(checkNumber(10)); console.log(checkStringOddOrEven('hello'));
index.js는 var.js와 func.js를 모두 참조하고, var.js는 func.js와 index.js에 두 번 쓰일 수 있다. - exports 객체로도 모듈을 만들 수 있다.
var.js
exports.odd = 'CJS 홀수입니다'; exports.even = 'CJS 짝수입니다';
module.exports로 한 번에 대입하는 대신, 각각의 변수를 exports 객체에 넣는다.
module.exports와 exports가 같은 객체를 참조하기 때문에 동일하게 동작한다.
** exports에는 반드시 속성명과 속성값을 대입하여,
module.exports와의 참조 관계가 깨지지 않도록 주의해야 한다.
** 참조 관계가 있으므로
한 모듈에 exports 객체와 module.exports를 동시에 사용하지 않는 것이 좋다.
** 노드에서 this
최상위 스코프에 존재하는 this는 module.exports를 가리킨다.
함수 선언문 내부의 this는 global 객체를 가리킨다.
③ 순환 참조(circular dependency)
- dep1.js
const dep2 = require('./dep2'); console.log('require dep2', dep2); module.exports = () => { console.log('dep2', dep2); };
- dep2.js
const dep1 = require('./dep1'); console.log('require dep1', dep1); module.exports = () => { console.log('dep1', dep1); };
- dep-run.js
const dep1 = require('./dep1'); console.log('require dep1', dep1); module.exports = () => { console.log('dep1', dep1); };
- dep-run.js를 실행하면
1) require('./dep1')이 실행된다.
2) dep1.js에서 require('./dep2')가 실행된다.
3) dep2.js에서는 require('./dep1')이 실행된다.
이 과정이 계속 반복되어 dep1의 module.exports가 함수가 아니라 빈 객체로 표시된다.
이러한 현상을 순환 참조(circular dependency)라고 한다.
순환 참조되는 대상은 에러 없이 빈 객체로 변경되므로 주의한다.
ECMAScript
① ECMAScript 모듈(ES 모듈)
- 표준 자바스크립트 모듈 형식으로, 사용 비율이 늘어나고 있다.
- 브라우저에서도 사용할 수 있어 브라우저와 노드에 같은 모듈 형식을 사용할 수 있다는 것이 장점이다.
② ECMAScript 모듈 사용법
- CommonJS의 require, exports, module.exports가 각각 import, export, export default로 바뀐다.
- 확장자는 js에서 mjs로 변경되고, 생략이 불가능하다.
var.mjs
export const odd = 'MJS 홀수입니다'; export const even = 'MJS 짝수입니다';
func.mjs
import { odd, even } from './var.mjs'; function checkOddOrEven(num) { if (num % 2) { // 홀수이면 return odd; } return even; } export default checkOddOrEven;
index.mjs
import { odd, even } from './var.mjs'; import checkNumber from './func.mjs'; function checkStringOddOrEven(str) { if (str.length % 2) { // 홀수이면 return odd; } return even; } console.log(checkNumber(10)); console.log(checkStringOddOrEven('hello'));
③ CommonJS vs ES 모듈
CommonJS 모듈 | ECMAScript 모듈 | |
문법 | require('./a'); module.exports = A; const A = require('./a'); exports.C = D; const E = F; exports.E = E; const { C, E } = require ('./b'); |
import './a.mjs'; export default A; import A from './a.mjs'; export const C = D; const E = F; export { E }; import { C, E } from './b.mjs'; |
확장자 | js cjs |
mjs js(package.json - type: "module") |
확장자 생략 | 가능 | 불가능 |
다이내믹 임포트 | 가능 | 불가능 |
인덱스(index) 생략 | 가능 ex) require('./folder')) |
불가능 ex) import './folder/index.mjs') |
top level await | 불가능 | 가능 |
__filename, __dirname, require, module.exports, exports |
사용 가능 | 사용 불가능 (import.meta.url 사용) |
서로 간 호출 | 가능 |
** 서로 간에 호환되지 않는 경우가 많으므로 한 가지 형식만 사용하는 것을 권장한다.
Dynamic Import (동적 불러오기)
- ES 모듈은 if문 안에서 import 하는 것이 불가능하므로,
import 함수로 모듈을 동적으로 불러온다. 이를 Dynamic Import라고 한다.
dynamic.mjs
const a = true; if (a) { const m1 = await import('./func.mjs'); console.log(m1); const m2 = await import('./var.mjs'); console.log(m2); }
** ES 모듈의 최상위 스코프에서는 async 함수 없이도 await 할 수 있다.
__filename, __dirname
- __filename과 __dirname 키워드를 통해 현재 파일명과 현재 파일 경로를 확인할 수 있다.
filename.js
console.log(__filename); // C:\Users\user_name\Desktop\filename.js console.log(__dirname); // C:\Users\user_name\Desktop
- ES 모듈에서는 __filename과 __dirname을 사용할 수 없다.
대신 import.meta.url로 경로를 가져올 수 있다.
filename.mjs
console.log(import.meta.url); // file:///C:/Users/user_name/Desktop/filename.mjs console.log(__filename); // ReferenceError: __filename is not defined in ES module scope
Quiz
- 콘솔에서 REPL로 들어가는 명령어는 ( ),
노드를 통해 파일을 실행하는 명령어는 ( )이다. - 노드에서는 ( )와 ( ) , 두 가지 형식의 모듈을 사용한다.
- CommonJS 형식에서 ( ) 함수로 모듈을 불러올 수 있다.
- ES 모듈에서는 __filename과 __dirname을 사용할 수 없는 대신 ( )로 경로를 가져온다.
Programming Quiz
1. CommonJS 형식으로 작성된 코드를 ECMAScript 모듈 형식으로 변경하시오.
const { name, number } = require('./var');
function getInfo() {
return `${name} ${number} Team`;
}
module.exports = getInfo;
정답
1. node, node [파일 경로]
2. CommonJS, ECMAScript
3. require
4. import.meta.url
1번
import { name, number } from './var.mjs';
function getInfo() {
return `${name} ${number} Team`;
}
export default getInfo;
출처 : 조현영, 『 Node.js 교과서 개정 3판』, 길벗(2022)
Corner Node.js 1
Editor : Snoopy
728x90