브라우저의 콘솔처럼 노드도 콘솔 기능을 제공한다. REPL
이라고 하며, 코드 읽기(Read
), 해석(Eval
), 결과 반환(Print
), 종료까지 반복(Loop
)의 약어이다.
노드를 설치했다면 터미널에 node
를 입력하여 진입하여 자바스크립트 코드를 작성한다. 종료는 .exit
을 입력한다.
$ node
Welcome to Node.js v18.13.0.
Type ".help" for more information.
> const x = "Hello Node"
undefined
> console.log(x)
Hello Node
undefined
> .exit
node
뒤에 js
확장자 파일명을 입력하면 터미널에서 해당 파일을 실행할 수 있다.
예를 들어, helloWorld.js
파일을 생성하여 다음 코드를 작성한다.
// helloWorld.js
function helloWorld(){
console.log("hello world");
helloNode();
};
function helloNode(){
console.log("hello node");
};
helloWorld();
터미널에서 node helloWorld.js
를 입력하면 파일의 코드가 실행된 후 종료된다.
$ node helloWorld.js
hello world
hello node
노드의 모듈에는 CommonJS 모듈
과 ECMAScript 모듈
이 있다.
자바스크립트 표준이 아닌 CommonJS 모듈
은 노드 생태계에서 가장 널리 쓰인다. 표준이 아님에도 많이 쓰인 이유는 표준 이전에 등장했기 때문이다.
// foo.js
function isOdd(x) {
return (x % 2) ? true : false;
};
module.exports = {
isOdd
}
/* or
exports.isOdd = function(x) {
return (x % 2) ? true : false;
}
*/
// bar.js
const { isOdd } = require("./foo");
console.log(isOdd(10));
/* or
const foo = require("./foo");
console.log(foo.isOdd(10));
*/
foo.js
는 홀짝을 판별하는 함수를 모듈로 내보내고 있다. bar.js
에서는 require("./foo")
를 통해 foo.js
가 내보낸 함수를 불러와 사용한다.
선언한 변수나 객체를 module.exports
에 객체로 담아 내보낼 수도 있지만, exports.변수(객체)명
으로도 내보낼 수 있다.
ES 모듈
은 자바스크립트 표준 모듈이다. 모듈을 내보내는 파일의 확장자는 .mjs
를 사용한다.
// foo.mjs
export function isOdd(x) {
return (x % 2) ? true : false;
};
// bar.mjs
import { isOdd } from "./foo.mjs";
console.log(isOdd(10));
/* or
import * as foo from "./foo.mjs";
console.log(foo.isOdd(10));
*/
파일에서 내보낼 변수나 객체를 export
한다. 구조 분해 할당으로 필요한 것만 import
하거나 as(alias)
를 사용하여 파일 전체를 import
할 수 있다.
만약 어떤 파일을 불러왔을 때 기본적으로 동작할 기능을 내보내야 한다면 export default
를 사용한다.
조건부로 모듈을 불러오는 것을 다이내믹 임포트(Dynamic Import)라고 한다. CommonJS 모듈
은 다이내믹 임포트가 가능하지만, ES 모듈
에서는 불가능하다.
// dynamic.js
const { isOdd } = require("./foo");
const x = 11;
if (isOdd(x)) {
const { helloWorld } = require("./helloWorld")
helloWorld()
}
/* 결과
$ node dynamic.js
hello world
hello node
*/
// dynamic.mjs
import { isOdd } from "./foo.mjs";
const x = 11;
if (isOdd(x)) {
const { helloWorld } = import("./helloWorld")
helloWorld()
}
/* 결과
$ node dynamic.mjs
file:///C:/.../learning_node.js/dynamic.mjs:7
helloWorld()
^
TypeError: helloWorld is not a function
at ?[90mfile:///C:/.../learning_node.js/?[39mdynamic.mjs:7:3
?[90m at ModuleJob.run (node:internal/modules/esm/module_job:194:25)?[39m
Node.js v18.13.0
*/
ES 모듈
에서 다이내믹 임포트를 사용할 때는 await
을 import
앞에 추가한다.
import { isOdd } from "./foo.mjs";
const x = 11;
if (isOdd(x)) {
const { helloWorld } = await import("./helloWorld.mjs")
helloWorld()
}
/* 결과
$ node dynamic.mjs
hello world
hello node
*.
노드는 __filename
과 __dirname
을 통해 파일 경로에 대한 정보를 제공한다.
// path.js
console.log(`filename: ${__filename}, dirname: ${__dirname}`)
/* 결과
$ node path.js
filename: C:\...\learning_node.js\path.js, dirname: C:\...\learning_node.js
*/
// path.mjs
console.log(`filename: ${__filename}, dirname: ${__dirname}`)
/* 결과
$ node path.mjs
file:///C:/.../learning_node.js/path.mjs:1
console.log(`filename: ${__filename}, dirname: ${__dirname}`)
^
ReferenceError: __filename is not defined in ES module scope
at ?[90mfile:///C:/.../learning_node.js/?[39mpath.mjs:1:26
?[90m at ModuleJob.run (node:internal/modules/esm/module_job:194:25)?[39m
Node.js v18.13.0
*/
ES 모듈
에서는 __filename
과 __dirname
이 동작하지 않는다. 대신 import.meta.url
로 경로를 가져올 수 있다.
// path.mjs
console.log(import.meta.url)
/* 결과
$ node path.mjs
file:///C:/.../learning_node.js/path.mjs
*/
브라우저의 window
와 같은 전역 객체이다. 별다른 호출없이 사용하는 require
나 console
등이 global
에 속해 있다.
주로 디버깅에 사용한다. 대표적으로 console.log
가 있다.
console.time(label)
: console.timeEnd(label)
과 대응되어 같은 label
을 가진 time
과 timeEnd
사이의 시간을 측정한다.console.error(error)
: error
내용을 표시한다.console.table(array)
: 배열을 테이블 형식으로 표현한다.console.dir(object, options?)
: 객체를 콘솔에 표시할 때 사용한다. 옵션을 통해 색을 추가(color
)하거나 객체 깊이(depth
)를 확인할 수 있다. depth
의 기본값은 2
이다.console.trace(label)
: 에러 추적에 사용한다.setTimeout(callback, delay)
: delay(ms)
이후에 callback
을 실행한다.setInterval(callback, delay)
: delay(ms)
마다 callback
을 반복 실행한다.setImmediate(callback)
: callback
을 즉시 실행한다.clearTimeout(id)
: setTimeout
을 취소한다.clearInterval(id)
: setInterval
을 취소한다.clearImmediate(id)
: setImmediate
를 취소한다.현재 실행되고 있는 노드 프로세스에 대한 정보를 담고 있다.
process.version
: 설치된 노드의 버전process.arch
: 프로세서 아키텍처 정보process.platform
: 운영체제 플랫폼 정보process.pid
: 현재 프로세스 아이디process.uptime()
: 프로세스 동작 시간. 단위는 초(second).process.execPath
: 노드 경로process.cwd()
: 현재 프로세스 실행 위치process.cpuUsage()
: 현재 cpu 사용량process.env
: 시스템의 환경 변수process.nextTick(callback)
: 이벤트 루프가 다른 콜백 함수보다 nextTick
의 콜백 함수를 우선 처리하도록 만든다.process.exit(code)
: 실행 중인 노드 프로세스를 종료한다. 서버를 멈추므로 특수한 경우에만 사용한다. code
로 아무것도 입력하지 않거나 0
을 주입하면 정상 종료, 1
을 주입하면 비정상 종료를 의미한다.노드 내에는 많은 모듈이 내장되어 있다. 모듈
or node:모듈
형식으로 호출하면 노드가 알아서 내장 모듈을 파악해 가져온다. os
를 예로 든다면 아래와 같다.
// os.js
const os = require("os"); // or const os = require("node:os");
// os.mjs
import os from "os"; // or import os from "node:os";
운영체제의 정보를 가져온다.
os.arch()
: process.arch
와 동일os.platform()
: process.platform
과 동일os.type()
: 운영체제 종류os.uptime()
: 운영체제 부팅 후 동작 시간(초)os.hostname()
: 컴퓨터 이름os.release()
: 운영체제 버전os.homedir()
: 홈 디렉토리 경로os.tmpdir()
: 임시 파일 저장 경로os.cpus()
: 컴퓨터 코어 정보os.freemem()
: 사용 가능한 메모리(RAM)os.totalmem()
: 전체 메모리 용량디렉토리와 파일 경로를 쉽게 조작하도록 도와준다. 운영체제마다 경로 구분자가 다르다. 윈도 타입
은 \
로, POSIX 타입
은 /
로 구분한다.
path.sep
: 경로 구분자(윈도 = \
, POSIX = /
)path.delimiter
: 환경 변수 구분자(윈도 = ;
, POSIX = :
)path.dirname(경로)
: 파일이 위치한 디렉토리 경로path.extname(경로)
: 파일 확장자path.basename(경로, 확장자)
: 확장자를 포함한 파일명 표시. 파일명만 표시하려면 두 번째 인수로 확장자를 넣는다.path.parse(경로)
: 파일 경로를 root, dir, base, ext, name
으로 분리path.format(객체)
: path.parse()
한 객체를 파일 경로로 병합path.normalize(경로)
: /
나 \
를 실수로 여러 번 사용했거나 혼용했을 때 정상적인 경로로 변환path.isAbsolute(경로)
: 파일 경로가 절대 경로인지 상대 경로인지 true/false
로 알려준다.path.relative(기준경로, 비교경로)
: 기준경로에서 비교경로로 가는 방법을 알려준다.path.join(경로, …)
: 여러 인수를 하나의 경로로 합친다. 맨 앞의 /
를 상대경로로 인식해 처리한다.path.join("/learning_node.js", "/foo.mjs")
➡️ \learning_node.js\foo.mjs
path.resolve(경로, …)
: path.join()
과 비슷하나, 맨 앞의 /
가 붙은 경로를 무시한다.path.resolve("/learning_node.js", "/foo.mjs")
➡️ C:\foo.mjs
윈도 타입
에서 POSIX 타입
을 사용하려면 path.posix.sep
등을 사용하고, 반대는 path.win32.sep
등을 사용한다.
인터넷 주소를 조작하는 모듈이다. url 형식은 웹 표준을 정하는 단체인 WHATWG 방식을 따른다.
URL
은 url 모듈
의 내장 객체이면서 노드의 내장 객체이기 때문에 따로 호출하지 않아도 사용할 수 있다. 아래는 new URL("http://example.com")
을 출력한 결과다.
URL {
href: 'http://example.com/',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/',
search: '',
searchParams: URLSearchParams {},
hash: ''
}
파싱된 url은 url.format()
으로 다시 병합할 수 있다.
host
없이 pathname
만으로는 주소를 처리할 수 없다. 이때는 new URL(pathname, host)
로 적어야 한다.
또한, 보통 데이터를 전달할 때 query string
을 통한다. url 마지막에 ?
로 시작하여 key=value
의 형태를 갖는다. searchParams
메서드가 이러한 부분을 처리한다.
URL {
href: 'http://example.com/?q=params',
// (...)
search: '?q=params',
searchParams: URLSearchParams { 'q' => 'params' },
// (...)
}
searchParams
에는 다음과 같은 메서드가 존재한다.
getAll(key)
: 키에 해당하는 모든 값을 가져온다.get(key)
: 키에 해당하는 첫 번째 값만 가져온다.has(key)
: 해당 키가 있는지 확인한다.keys()
: 모든 키를 iterable한 객체로 가져온다.values()
: 모든 값을 iterable한 객체로 가져온다.append(key, value)
: 해당 키를 추가한다. 같은 키의 값이 있으면 유지하고 추가한다.set(key, value)
: 모든 키-값을 지우고 새로 추가한다.delete(key)
: 해당 키를 제거한다.toString()
: 조작한 searchParams
객체를 문자열로 만든다.