Node.jsには、ブラウザのJavaScriptにはない固有のグローバルオブジェクトやAPIが多数存在します。これらを理解することは、環境変数の管理、プロセス制御、バイナリデータ操作といった実践的なサーバーサイド開発の基盤となります。本記事では、processオブジェクト、global/globalThisBufferクラス、そして__dirname__filenameについて、実用的なサンプルとともに解説します。

実行環境

項目 バージョン
Node.js 20.x LTS以上
npm 10.x以上
OS Windows/macOS/Linux

前提条件

  • JavaScriptの基礎文法を理解していること
  • Node.jsがインストール済みであること

グローバルオブジェクト(global / globalThis)

globalオブジェクトとは

Node.jsにおけるglobalオブジェクトは、ブラウザにおけるwindowオブジェクトに相当するグローバル名前空間です。どのモジュールからでもアクセスできるオブジェクトやメソッドがここに格納されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// グローバルオブジェクトの確認
console.log(global);
// 大量のプロパティが出力される

// よく使うグローバルに利用可能なもの
console.log(typeof setTimeout);   // 'function'
console.log(typeof setInterval);  // 'function'
console.log(typeof console);      // 'object'
console.log(typeof process);      // 'object'
console.log(typeof Buffer);       // 'function'

globalThisの登場

ES2020で導入されたglobalThisは、実行環境に依存しない標準的なグローバルオブジェクト参照です。Node.jsではglobalと同じオブジェクトを参照しますが、ブラウザやWeb Workerなど異なる環境でも同じ構文で利用できます。

1
2
3
4
5
6
// Node.jsではglobalとglobalThisは同一
console.log(global === globalThis);  // true

// 環境に依存しないコードを書く場合はglobalThisを推奨
globalThis.myGlobalVar = 'Hello, Node.js';
console.log(global.myGlobalVar);     // 'Hello, Node.js'

ブラウザとの違い

Node.jsのグローバルスコープは、ブラウザとは異なる動作をします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// ブラウザでは、トップレベルのvarはwindowプロパティになる
// var x = 10; → window.x === 10

// Node.jsでは、モジュール内のvarはグローバルにならない
var localVar = 'module-local';
console.log(global.localVar);  // undefined

// 明示的にglobalに代入する必要がある
global.explicitGlobal = 'This is global';
console.log(global.explicitGlobal);  // 'This is global'

主なグローバルオブジェクト一覧

以下はNode.jsで利用できる主要なグローバルオブジェクトです。

オブジェクト 説明
console 標準出力・エラー出力への書き込み
process 現在のNode.jsプロセスに関する情報と制御
Buffer バイナリデータを扱うクラス
setTimeout/setInterval タイマー関数
setImmediate イベントループの次回反復で実行
queueMicrotask マイクロタスクキューへの追加
URL/URLSearchParams URL操作
TextEncoder/TextDecoder 文字列とバイナリの変換
fetch HTTP通信(Node.js 18以降でネイティブサポート)

processオブジェクト

processオブジェクトは、現在実行中のNode.jsプロセスに関する情報を提供し、プロセスを制御するためのメソッドを持つグローバルオブジェクトです。

process.env - 環境変数の操作

process.envは、システムの環境変数を含むオブジェクトです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 環境変数の読み取り
console.log(process.env.PATH);      // システムのPATH環境変数
console.log(process.env.NODE_ENV);  // 'development' or 'production'

// 環境変数の設定(Node.jsプロセス内のみ有効)
process.env.MY_APP_PORT = '3000';
console.log(process.env.MY_APP_PORT);  // '3000'

// 環境変数の値は常に文字列
process.env.PORT = 8080;  // 数値を代入しても...
console.log(typeof process.env.PORT);  // 'string'
console.log(process.env.PORT);         // '8080'

// 環境変数の削除
delete process.env.MY_APP_PORT;
console.log(process.env.MY_APP_PORT);  // undefined

実践的な環境変数の利用パターン

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// config.js - 環境変数を一元管理
const config = {
  port: parseInt(process.env.PORT, 10) || 3000,
  nodeEnv: process.env.NODE_ENV || 'development',
  databaseUrl: process.env.DATABASE_URL,
  apiKey: process.env.API_KEY,
};

// 必須環境変数のチェック
const requiredEnvVars = ['DATABASE_URL', 'API_KEY'];
for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    console.error(`Missing required environment variable: ${envVar}`);
    process.exit(1);
  }
}

module.exports = config;

.envファイルの読み込み(Node.js 20.6以降)

Node.js 20.6以降では、--env-fileフラグを使用して.envファイルを直接読み込めます。

1
2
3
4
5
6
# .envファイルを作成
echo "PORT=4000" > .env
echo "NODE_ENV=development" >> .env

# --env-fileフラグで読み込み
node --env-file=.env app.js

また、process.loadEnvFile()メソッドを使用してプログラム内から読み込むこともできます。

1
2
3
// Node.js 20.6+
process.loadEnvFile('.env');
console.log(process.env.PORT);  // '4000'

process.argv - コマンドライン引数

process.argvは、Node.jsプロセス起動時に渡されたコマンドライン引数を含む配列です。

1
2
// cli-example.js
console.log('process.argv:', process.argv);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ node cli-example.js --name=John --age=30 hello world

# 出力:
# process.argv: [
#   '/usr/local/bin/node',       // index 0: Node.js実行ファイルのパス
#   '/path/to/cli-example.js',   // index 1: 実行スクリプトのパス
#   '--name=John',               // index 2以降: 引数
#   '--age=30',
#   'hello',
#   'world'
# ]

実用的な引数パース

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// parse-args.js
const args = process.argv.slice(2);  // 最初の2つ(node, script)を除外

// シンプルな引数パーサー
function parseArgs(args) {
  const result = { _: [] };  // アンダースコアには位置引数を格納
  
  for (const arg of args) {
    if (arg.startsWith('--')) {
      const [key, value] = arg.slice(2).split('=');
      result[key] = value !== undefined ? value : true;
    } else if (arg.startsWith('-')) {
      const key = arg.slice(1);
      result[key] = true;
    } else {
      result._.push(arg);
    }
  }
  
  return result;
}

const parsed = parseArgs(args);
console.log(parsed);
// { _: ['hello', 'world'], name: 'John', age: '30' }

Node.js組み込みの引数パーサー(Node.js 18.3以降)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Node.js 18.3+では util.parseArgs が利用可能
const { parseArgs } = require('node:util');

const options = {
  name: { type: 'string', short: 'n' },
  age: { type: 'string', short: 'a' },
  verbose: { type: 'boolean', short: 'v' },
};

try {
  const { values, positionals } = parseArgs({ options, allowPositionals: true });
  console.log('values:', values);
  console.log('positionals:', positionals);
} catch (err) {
  console.error(err.message);
}

process.cwd() - 現在の作業ディレクトリ

process.cwd()は、Node.jsプロセスが起動された現在の作業ディレクトリを返します。

1
2
3
4
5
6
7
8
// 現在の作業ディレクトリを取得
console.log('Current working directory:', process.cwd());
// 例: /Users/username/projects/my-app

// 作業ディレクトリの変更
process.chdir('/tmp');
console.log('Changed to:', process.cwd());
// 例: /tmp

process.exit() - プロセスの終了

process.exit()は、Node.jsプロセスを終了させます。引数として終了コードを指定できます。

1
2
3
4
5
6
7
8
9
// 正常終了(終了コード0)
process.exit(0);

// エラー終了(終了コード1)
process.exit(1);

// 終了コードを設定してから自然終了
process.exitCode = 1;
// プロセスは残りの処理を完了してから終了コード1で終了

終了コードの規約

コード 意味
0 正常終了
1 一般的なエラー
2 コマンドライン引数の誤用
126 コマンドが実行不可
127 コマンドが見つからない
128+ シグナルによる終了(128 + シグナル番号)

安全な終了処理

process.exit()を直接呼び出すと、未完了の非同期処理が中断される可能性があります。代わりにprocess.exitCodeを使用する方法が推奨されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 非推奨: 非同期処理が中断される可能性
async function riskyExit() {
  await saveData();  // この処理が完了しない可能性
  process.exit(0);
}

// 推奨: 非同期処理の完了を待つ
async function safeExit() {
  try {
    await saveData();
    process.exitCode = 0;
  } catch (error) {
    console.error('Failed to save data:', error);
    process.exitCode = 1;
  }
}

その他の便利なprocessプロパティ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Node.jsのバージョン
console.log('Node.js version:', process.version);
// 例: v20.11.0

// プロセスID
console.log('Process ID:', process.pid);
// 例: 12345

// プラットフォーム
console.log('Platform:', process.platform);
// 例: 'darwin', 'linux', 'win32'

// CPU アーキテクチャ
console.log('Architecture:', process.arch);
// 例: 'x64', 'arm64'

// メモリ使用量
console.log('Memory usage:', process.memoryUsage());
// { rss: 12345678, heapTotal: 1234567, heapUsed: 123456, ... }

// プロセス稼働時間(秒)
console.log('Uptime:', process.uptime());
// 例: 120.456

// 高精度タイマー(ナノ秒)
const start = process.hrtime.bigint();
// 何らかの処理
const end = process.hrtime.bigint();
console.log(`処理時間: ${end - start} ns`);

processイベント

processオブジェクトはEventEmitterを継承しており、様々なイベントをリッスンできます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// プロセス終了前のイベント
process.on('beforeExit', (code) => {
  console.log('Process beforeExit event with code:', code);
});

// プロセス終了イベント
process.on('exit', (code) => {
  console.log('Process exit event with code:', code);
  // 同期処理のみ実行可能(非同期処理は無視される)
});

// 未捕捉の例外
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  process.exit(1);
});

// 未処理のPromise rejection
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});

// シグナル(SIGINT: Ctrl+C)
process.on('SIGINT', () => {
  console.log('Received SIGINT. Graceful shutdown...');
  // クリーンアップ処理
  process.exit(0);
});

Bufferクラス

Bufferクラスは、バイナリデータを直接操作するためのNode.js固有のクラスです。TCP ストリームやファイルシステム操作など、バイナリデータを扱う場面で広く使用されます。

Bufferの作成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 文字列からBufferを作成(最も一般的)
const buf1 = Buffer.from('Hello, Node.js');
console.log(buf1);
// <Buffer 48 65 6c 6c 6f 2c 20 4e 6f 64 65 2e 6a 73>
console.log(buf1.toString());
// 'Hello, Node.js'

// 配列からBufferを作成
const buf2 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
console.log(buf2.toString());
// 'Hello'

// 指定サイズの初期化済みBufferを作成(ゼロ埋め)
const buf3 = Buffer.alloc(10);
console.log(buf3);
// <Buffer 00 00 00 00 00 00 00 00 00 00>

// 指定サイズの未初期化Bufferを作成(高速だが安全でない)
const buf4 = Buffer.allocUnsafe(10);
// 古いメモリの内容が残っている可能性があるため注意

文字エンコーディング

Bufferは様々な文字エンコーディングをサポートしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const text = 'こんにちは';

// UTF-8(デフォルト)
const utf8Buf = Buffer.from(text, 'utf8');
console.log(utf8Buf);
// <Buffer e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af>
console.log(utf8Buf.toString('utf8'));
// 'こんにちは'

// Base64エンコーディング
const base64Buf = Buffer.from('SGVsbG8gV29ybGQ=', 'base64');
console.log(base64Buf.toString());
// 'Hello World'

// 文字列をBase64に変換
const originalText = 'Node.js Buffer';
const base64String = Buffer.from(originalText).toString('base64');
console.log(base64String);
// 'Tm9kZS5qcyBCdWZmZXI='

// Hexエンコーディング
const hexBuf = Buffer.from('48656c6c6f', 'hex');
console.log(hexBuf.toString());
// 'Hello'

Bufferの操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const buf = Buffer.alloc(10);

// 書き込み
buf.write('Hello');
console.log(buf);
// <Buffer 48 65 6c 6c 6f 00 00 00 00 00>

// インデックスアクセス
buf[5] = 0x21;  // '!'のASCIIコード
console.log(buf.toString());
// 'Hello!'(残りはnull文字)

// スライス(元のBufferと同じメモリを参照)
const slice = buf.subarray(0, 5);
console.log(slice.toString());
// 'Hello'

// コピー(独立したメモリ領域)
const copy = Buffer.from(buf);

// 結合
const buf1 = Buffer.from('Hello, ');
const buf2 = Buffer.from('World!');
const combined = Buffer.concat([buf1, buf2]);
console.log(combined.toString());
// 'Hello, World!'

// 比較
const bufA = Buffer.from('abc');
const bufB = Buffer.from('abc');
const bufC = Buffer.from('xyz');
console.log(bufA.equals(bufB));  // true
console.log(bufA.equals(bufC));  // false
console.log(bufA.compare(bufC)); // -1(bufA < bufC)

Bufferとバイナリ数値

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const buf = Buffer.alloc(8);

// 整数の書き込み
buf.writeUInt32BE(0x12345678, 0);  // ビッグエンディアン
buf.writeUInt32LE(0x12345678, 4);  // リトルエンディアン
console.log(buf);
// <Buffer 12 34 56 78 78 56 34 12>

// 整数の読み取り
console.log(buf.readUInt32BE(0).toString(16));  // '12345678'
console.log(buf.readUInt32LE(4).toString(16));  // '12345678'

// 浮動小数点数
const floatBuf = Buffer.alloc(4);
floatBuf.writeFloatLE(3.14);
console.log(floatBuf.readFloatLE());  // 3.140000104904175

BufferとTypedArray

BufferUint8Arrayを継承しているため、TypedArrayのメソッドも利用できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const buf = Buffer.from([1, 2, 3, 4, 5]);

// ArrayLikeメソッドが使える
console.log(buf.map(x => x * 2));
// Uint8Array(5) [ 2, 4, 6, 8, 10 ]

// for...ofでイテレーション
for (const byte of buf) {
  console.log(byte);
}
// 1, 2, 3, 4, 5

// ArrayBufferとの変換
const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
console.log(new Uint8Array(arrayBuffer));
// Uint8Array(5) [ 1, 2, 3, 4, 5 ]

実践的なBuffer活用例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const fs = require('node:fs');
const crypto = require('node:crypto');

// ファイルのハッシュ計算
function computeFileHash(filePath) {
  const buffer = fs.readFileSync(filePath);
  const hash = crypto.createHash('sha256');
  hash.update(buffer);
  return hash.digest('hex');
}

// バイナリプロトコルの解析例
function parseHeader(buffer) {
  return {
    version: buffer.readUInt8(0),
    type: buffer.readUInt8(1),
    length: buffer.readUInt16BE(2),
    timestamp: buffer.readUInt32BE(4),
  };
}

const headerBuf = Buffer.from([0x01, 0x02, 0x00, 0x64, 0x65, 0x8d, 0x4c, 0x00]);
console.log(parseHeader(headerBuf));
// { version: 1, type: 2, length: 100, timestamp: 1703730176 }

__dirname と __filename

__dirname__filenameは、現在実行中のファイルのディレクトリパスとファイルパスを提供する変数です。ただし、これらはCommonJSモジュールでのみ利用可能であり、ES Modulesでは別の方法が必要です。

CommonJSでの使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// /home/user/project/src/utils/helper.js

console.log('__dirname:', __dirname);
// '/home/user/project/src/utils'

console.log('__filename:', __filename);
// '/home/user/project/src/utils/helper.js'

// ファイルパスの構築に活用
const path = require('path');
const configPath = path.join(__dirname, '..', 'config', 'settings.json');
console.log('Config path:', configPath);
// '/home/user/project/src/config/settings.json'

ES Modulesでの代替手段

ES Modules(.mjsファイルまたは"type": "module"を設定したプロジェクト)では、__dirname__filenameは利用できません。代わりにimport.meta.urlを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// helper.mjs(ES Module)
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

// __filenameの代替
const __filename = fileURLToPath(import.meta.url);
console.log('__filename:', __filename);

// __dirnameの代替
const __dirname = dirname(__filename);
console.log('__dirname:', __dirname);

// パスの構築
const configPath = join(__dirname, '..', 'config', 'settings.json');
console.log('Config path:', configPath);

process.cwd() との違い

__dirname(またはimport.meta.urlから導出したパス)とprocess.cwd()は異なる概念です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// /home/user/project/src/index.js

console.log('__dirname:', __dirname);
// '/home/user/project/src'(ファイルの場所)

console.log('process.cwd():', process.cwd());
// 実行時のカレントディレクトリに依存

// 例: cd /home/user && node project/src/index.js
// __dirname: '/home/user/project/src'
// process.cwd(): '/home/user'
変数/関数 意味 用途
__dirname ファイルが存在するディレクトリ ファイル相対パスの構築
__filename 実行中のファイルのパス ファイル名の取得、ログ出力
process.cwd() プロセス起動時のカレントディレクトリ ユーザーが指定した相対パスの解決

実践的な使い分け

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const path = require('path');
const fs = require('fs');

// プロジェクト内の静的ファイルを読み込む場合は __dirname を使用
// (どのディレクトリから実行されても正しく動作する)
const templatePath = path.join(__dirname, 'templates', 'email.html');
const template = fs.readFileSync(templatePath, 'utf8');

// ユーザーが指定した相対パスを解決する場合は process.cwd() を使用
// (例: CLIツールで引数として渡されたパス)
const userSpecifiedPath = process.argv[2];
const absolutePath = path.resolve(process.cwd(), userSpecifiedPath);

まとめ

本記事では、Node.js固有のグローバルオブジェクトとAPIについて解説しました。

  • global/globalThisはNode.jsのグローバル名前空間であり、ブラウザのwindowに相当します
  • processオブジェクトは、環境変数(env)、コマンドライン引数(argv)、プロセス制御(exit)、作業ディレクトリ(cwd)など、プロセス管理に必要な機能を提供します
  • Bufferクラスは、バイナリデータの効率的な操作を可能にし、ファイルI/Oやネットワーク通信で不可欠です
  • __dirname/__filenameはCommonJS固有の変数であり、ES Modulesではimport.meta.urlを使用します

これらの基本を理解することで、Node.jsでの実践的なサーバーサイド開発の土台が築けます。次のステップとして、非同期I/Oやモジュールシステムについてさらに学習を進めていくことをおすすめします。

参考リンク