関数(引数・戻り値・スコープ)
入力(引数)を受け取り、処理して、結果(戻り値)を返す“ひとかたまり”。同じ処理を名前で何度も呼び出せる、再利用の基本単位。
- 1.関数は 入力(引数)→ 処理 → 出力(戻り値) をまとめた再利用の単位。
- 2.引数の渡り方は“値渡し”と“参照渡し”。オブジェクトや配列は中身を書き換えると呼び出し元にも影響しがち。
- 3.外の状態を変えず戻り値だけで結果を返す“純粋関数”は、テストしやすく安全。
なぜ関数にまとめるのか
同じ処理を何度もコピペすると、修正のたびに全部を直すことになり、直し忘れがバグになります。処理を関数にまとめると、
- 名前が付くので「何をするか」が読んで分かる(
calcTaxなど) - 1か所を直せば全呼び出しに反映される(DRY: 繰り返しを避ける)
- 中の実装を知らなくても、入力と出力だけ理解すれば使える(ブラックボックス化)
// 定義(design)
function calcTax(price) {
return Math.floor(price * 1.1); // 戻り値を返す
}
// 呼び出し(call)
calcTax(1000); // 1100
calcTax(298); // 327
引数と戻り値
- 引数(ひきすう / argument・parameter): 関数に渡す入力。
function f(a, b)のa, bが受け取り口。 - 戻り値(return value): 関数が返す結果。
returnで返す。returnを書かない/値を付けないと、多くの言語で「何もない」(undefined・Noneなど)が返ります。
def greet(name, greeting="こんにちは"): # デフォルト引数
return f"{greeting}, {name}さん"
greet("田中") # "こんにちは, 田中さん"
greet("佐藤", "おはよう") # "おはよう, 佐藤さん"
return に到達した瞬間、関数の処理は終了して呼び出し元に戻ります。その後ろの行は実行されません。早期 return(ガード節)で「ありえない入力なら即抜ける」と書くと、ネストの深い if を減らせます。
値渡しと参照渡し(最大のつまずき)
「引数を渡す」とき、値そのものを渡すのか、値の置き場所(参照)を渡すのかで挙動が変わります。
| 観点 | 値渡し(call by value) | 参照渡し / 共有渡し |
|---|---|---|
| 渡るもの | 値のコピー | 実体への参照(同じ実体を共有) |
| 関数内で再代入 | 呼び出し元に影響しない | (多くの言語で)影響しない |
| 中身を書き換え | 影響しない | 呼び出し元のオブジェクト/配列も変わる |
| 代表的な対象 | 数値・真偽値・文字列などプリミティブ | オブジェクト・配列・リスト |
JavaScript や Python の実体は厳密には「共有渡し(call by sharing)」で、参照の値がコピーされて渡る仕組みです。難しく聞こえますが、結論はシンプル——「オブジェクトや配列を関数に渡して中身を書き換えると、呼び出し元にも反映される」。
function addItem(arr) {
arr.push("🍎"); // 中身を変更 → 呼び出し元に影響する
}
const fruits = [];
addItem(fruits);
fruits; // ["🍎"] ← 元の配列が変わった!
function reassign(arr) {
arr = ["別物"]; // 再代入は“別の箱”を指すだけ → 呼び出し元は不変
}
reassign(fruits);
fruits; // ["🍎"] ← 変わらない
「渡されたオブジェクトを関数内で書き換える」のは、呼び出し元から見ると気づきにくい副作用です。バグの温床になりがち。元を壊したくないなら、[...arr](コピー)や {...obj} を作ってから操作するか、新しい値を return で返しましょう。
スコープ:変数が見える範囲
スコープとは「その変数を参照できる範囲」のこと。関数の中で宣言した変数(ローカル変数)は、その関数の外からは見えません。これが、関数同士が変数名でぶつからずに済む理由です。
| 種類 | 見える範囲 | 性質 |
|---|---|---|
| ローカル | 宣言した関数/ブロックの内側だけ | 外から触れない・関数を抜けると消える |
| グローバル | プログラムのどこからでも | 便利だが、どこから変わるか追えず壊れやすい |
const total = 100; // グローバル
function calc() {
const tax = 10; // ローカル:calc の中だけ
return total + tax; // 外側(グローバル)は読める
}
calc(); // 110
// tax; // ← ここでは参照できない(エラー)
どこからでも書き換えられるグローバル変数は、規模が大きくなると「いつ・誰が変えたか」を追えなくなります。値は基本ローカルに閉じ込め、必要なものだけ引数で渡し、結果は戻り値で受け取るのが安全です。
クロージャ:関数が“環境”を覚える
クロージャとは、関数が、自分が定義された場所のローカル変数を覚えたまま持ち運べる仕組み。外側の関数が終了した後でも、内側の関数はその変数にアクセスし続けられます。
function makeCounter() {
let count = 0; // 外側のローカル変数
return function () {
count += 1; // それを覚えている
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2 ← count が保持されている
count は外から直接触れない(カプセル化)のに、counter() を呼ぶたびに状態が積み上がります。状態を隠して持つ・設定を固定した関数を作る(部分適用)など、クロージャは応用が広い概念です。
副作用と純粋関数
- 副作用(side effect): 戻り値を返す以外に、外の世界に影響を与えること(グローバル変数や引数の書き換え、画面出力、ファイル・通信など)。
- 純粋関数(pure function): ①同じ入力なら必ず同じ出力を返し、②副作用がない関数。
// 純粋:入力だけで出力が決まる・外を変えない
const add = (a, b) => a + b;
// 不純:外部状態に依存し、外を書き換える
let rate = 1.1;
function withTax(p) {
rate = 1.08; // 外を変更(副作用)
return p * rate; // 結果が外部状態に左右される
}
純粋関数は「入力 → 出力」だけを確かめればよく、外部の状態を用意しなくてもテストできます。まず処理を純粋関数で組み、副作用(保存・表示・通信)は外側の薄い層に追い出す——これが壊れにくいコードの定石です。
つまずきポイントまとめ
| よくある誤解 | 実際は |
|---|---|
| 引数を渡せば元の値は安全 | オブジェクト/配列は中身を書き換えると元も変わる |
| return を書かなくても結果が返る | 返らない(undefined・None 等)。値は明示的に return する |
| 関数内の変数は外でも使える | ローカル変数は関数の外からは見えない |
| 関数は短く分けるほど常に良い | “1つの責務”が目安。分けすぎても追いにくくなる |
どんな時に意識する?
プログラミング Article
関数(引数・戻り値・スコープ)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
関数
比較で見る軸
難易度: basic / カテゴリ: プログラミング / タグ数: 4
導入後に効く点
引数の渡り方は“値渡し”と“参照渡し”。オブジェクトや配列は中身を書き換えると呼び出し元にも影響しがち。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- basic
- カテゴリ
- プログラミング
- タグ数
- 4
判断チェックリスト
- 自社の用途が「関数 / スコープ」に近いか確認する。
- 強みである「関数は 入力(引数)→ 処理 → 出力(戻り値) をまとめた再利用の単位。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。