1.関数とは何か — 入力を受け取って結果を返す機械
第1講では、プログラムを入力 → 処理 → 出力として見ました。関数は、その構造を小さく切り出して名前を付けたものです。自動販売機を思い浮かべるとわかりやすいでしょう。お金を入れてボタンを押せば(入力)、中で何が起きているか知らなくても飲み物(結果)が出てきます。一度作っておけば、同じ自動販売機を何度でも使えます。
関数がなければ、同じ計算を使うたびにコードをコピーしなければなりません。そのうち計算のルールが変わると、コピーした場所をすべて探して直す必要があり、一か所でも直し忘れれば結果が食い違います。関数にしておけばルールは一か所にしかなく、直すときもそこだけ直せば済みます。また vatOf(price) のように名前を見るだけで何をするのかわかるので、コードが文章のように読めます。
関数を作ることを「定義する」、使うことを「呼び出す」と言います。定義しただけでは何も起きません。名前のあとにかっこを付けて vatOf(10000) のように呼び出して、はじめて本体が実行されます。かっこを付けずに vatOf とだけ書くと関数そのものを指すだけで実行はされないので、注意してください。
function vatOf(price) {
return price * 0.1;
}
console.log(vatOf(10000));
console.log(vatOf(25000));1000 2500
2.引数と戻り値
関数名のあとのかっこの中にある price を引数(仮引数)と言います。関数の中で使う「空欄の名前」です。呼び出すときに渡す実際の値 10000 は実引数と呼びます。呼び出すと、実引数が引数に入った状態で本体が実行されます。引数が複数あるときはカンマで区切り、実引数は書いた順番どおりに入ります。順番を入れ替えて渡すとエラーなしにとんでもない結果が出るので、順番が大切です。
return は結果を呼び出し元に返し、関数をその場で終わらせます。return より下にある行は実行されません。return がないか、値なしで return; とだけ書くと、関数は undefined を返します。実引数を渡し忘れた場合も、足りない引数は undefined になり、計算に使われると第2講で見た NaN が出ます。JavaScript はこうした場合でもエラーを出さないので、自分で確かめる必要があります。
実引数がないときに使う値をあらかじめ決めておくこともできます。引数のあとに = 値 を付けるとデフォルト値になります。下のコードでは rate を渡さなければ0.1が使われます。デフォルト値は「ふつうはこの値」という設定によく合いますが、必ず受け取るべき値にデフォルト値を付けると、うっかり渡し忘れても気づけないので、使いどころを選びましょう。
undefined → NaN、デフォルト値があればその値function rectArea(w, h) {
return w * h;
}
console.log(rectArea(3, 4));
console.log(rectArea(3));
function tax(price, rate = 0.1) {
return price * rate;
}
console.log(tax(20000));
console.log(tax(20000, 0.05));12 NaN 2000 1000
3.`return` と `console.log` — いちばんよくある混同
関数を学び始めたときにいちばん混同しやすいのが、「返すこと」と「画面に出すこと」の違いです。どちらも結果が見えるように思えますが、していることはまったく違います。console.log は人が見るために値を画面に書き出すもので、プログラムはその値を続けて使えません。return は値を呼び出したコードに手渡すもので、受け取った側は変数に入れたり、別の計算に使ったりできます。
下のコードの showDouble は結果を出力するだけで、返しません。そのため showDouble(4) を変数に入れると、画面には8が出ますが変数には undefined が入り、それに1を足すと NaN になります。電卓をたたいて答えを画面に表示したことと、その答えを次の計算に引き渡したことの違いだと考えればよいでしょう。
このページの実習の採点も同じ仕組みです。採点機は関数を呼び出し、「返ってきた値」を期待値と比べます。関数の中で正解を console.log で出力するだけだと、画面には正しい数字が見えても採点は失敗します。原則は簡単です。計算する関数は return で返し、画面に出す作業は関数を呼び出した外側で行います。
function showDouble(x) {
console.log(x * 2);
}
function double(x) {
return x * 2;
}
const a = showDouble(4);
console.log('a の中身', a, a + 1);
const b = double(4);
console.log('b の中身', b, b + 1);8 a の中身 undefined NaN b の中身 8 9
| `return` | `console.log` | |
|---|---|---|
| 誰に向けて | 関数を呼び出したコード | 画面を見る人 |
| 値を続けて使えるか | 使える(変数・計算に使用) | 使えない |
| 関数は終わるか | その場で終わる | そのまま次の行へ進む |
| 実習の採点 | 返した値で採点 | 採点には使われない |
| 主に使う場所 | 計算する関数の中 | 確認・デバッグ、最終的な出力 |
4.アロー関数 — 短く書く別の文法
関数は const 名前 = (引数) => 式 という形でも書けます。これをアロー関数と言います。矢印の右側が式一つだけなら、その式の値が自動的に返されるので return は書きません。第6講で学ぶ map・filter のように関数をほかの関数に渡すときに特によく使われ、AIが書いたコードでもよく見かけます。
注意すべき落とし穴が一つあります。矢印の右側に波かっこを書くと、そこからは通常の関数の本体として扱われ、return を自分で書かなければなりません。下の bad は波かっこの中に式だけを書いて return を忘れたため、undefined を返します。エラーが出ないので、結果を出力してみるまで気づかずに見過ごしがちです。短ければ波かっこなし、複数行なら波かっこと return をセットで、と覚えておきましょう。
function で書いた関数とアロー関数は、この講座で扱う範囲では同じ働きをします。細かな違い(たとえば this の扱い方)はありますが、基礎の段階では知らなくてもかまいません。どちらかが「優れている」わけではないので、一緒に働く人やプロジェクトが使っている書き方に合わせれば十分です。
return を自分で書くconst add = (a, b) => a + b;
const square = (x) => x * x;
const bad = (x) => { x * x; };
const good = (x) => {
const y = x * x;
return y;
};
console.log(add(2, 3), square(4));
console.log(bad(4), good(4));5 16 undefined 16
5.関数の中の変数は関数の中だけ — スコープ
関数の中で let や const で作った変数は、その関数の中でしか見えません。これを有効範囲(スコープ)と言います。関数が終わるとその中の変数も消えるので、外側でその名前を使うと ReferenceError が出ます。エラーメッセージの is not defined は「その名前はここからは見えない」という意味です。メッセージの正確な文言はブラウザーによって少しずつ違うことがあります。
はじめは不便に思えますが、この規則のおかげで関数どうしが互いに邪魔をしません。いくつもの関数がそれぞれの中で total という名前を使っても混ざりません。関数の中で計算した値を外で使いたいなら、外の変数をこっそり書き換えるのではなく return で返してください。繰り返し文や条件文の波かっこの中で作った let・const も同じく、その波かっこの中でしか見えません(第4講で累積用の変数を繰り返し文の上に置いた理由です)。
function makeTotal() {
const inside = 100;
return inside + 1;
}
console.log(makeTotal());
console.log(inside);101
ReferenceError: inside is not defined6.小さな関数に分ける
長い計算をひとかたまりで書くと、どこで間違えたのか探しにくくなります。代わりに「一つのことだけをする」小さな関数をいくつも作って組み立てれば、部品ごとに別々に試せるうえ、名前が説明の役目を果たします。関数名は getTotal、isAdult のように、することを動詞で表します。真偽を返す関数は is・has で始める慣習があります。
分ける場所を見つけるための問いは、「この部分を一文で説明できるか」です。「商品の価格をすべて足す」「合計に応じて送料を決める」のように一文になれば、それが関数一つです。説明に「そして」が何度も入るなら、まだ分けられるという合図です。ただし一行で済む計算を細かく刻みすぎるとかえって読みにくくなるので、名前を付けるだけの意味がある単位で分けましょう。
function subtotal(prices) {
let sum = 0;
for (const p of prices) {
sum += p;
}
return sum;
}
function shippingFee(sum) {
return sum >= 50000 ? 0 : 3000;
}
function orderTotal(prices) {
const sum = subtotal(prices);
return sum + shippingFee(sum);
}
console.log(orderTotal([20000, 10000]));
console.log(orderTotal([30000, 20000]));33000 50000
- ステップ1 文に分ける: 「価格をすべて足す」/「合計から送料を決める」/「二つを足して最終金額を出す」。
- ステップ2 部品の関数:
subtotal(prices)は第4講の累積パターン、shippingFee(sum)は第3講の条件文です。 - ステップ3 組み立て:
orderTotal(prices)は二つの部品を呼び出すだけです。ルールが変われば(例: 基準が60,000ウォン)shippingFeeの一か所だけを直します。 - 検算: [20000, 10000] → 合計30,000 + 送料3,000 = 33,000。[30000, 20000] → 合計50,000(境界値で「以上」なので無料)= 50,000。
条件 ? 値1 : 値2 は、条件が真なら値1、偽なら値2になる短い条件式(三項演算子)です。第3講の if/else を一行で書いたものと考えればよいでしょう。長くなるなら if で書いたほうが読みやすくなります。7.純粋関数とテストしやすいコード
同じ入力を渡せばいつも同じ結果を返し、外側の変数や画面などを変えない関数を純粋関数と言います。double(4) はいつ呼び出しても8です。一方、下の addVisit は外側の変数 visits を変えるので、同じ呼び出しが呼ぶたびに違う値を返します。こうした関数は、結果が「これまでに何が起きたか」によって変わるので、原因を追いにくくなります。
純粋関数の最大の長所は、テストが簡単なことです。「この入力ならこの結果」という表さえあればよいからです。関数を作ったら、ふつうの場合、境界値(0、空のリスト、基準とぴったり同じ値)、おかしな入力をいくつか選んで先に期待値を書き、結果と比べてみてください。このページの実習の採点方法がまさにこれで、第10講でAIの書いたコードを検証するときも同じ方法を使います。
もちろん、すべての関数を純粋にできるわけではありません。画面に出す、ファイルを保存する、サーバーに送るといった作業は、外側を変えることそのものが目的です。コツは、計算は純粋関数として切り分けておき、外側を変える作業は端の数か所にまとめることです。そうすれば間違えやすい計算の部分は表で試せ、外側を変える部分は短いので目で確かめやすくなります。
let visits = 0;
function addVisit() {
visits++;
return visits;
}
console.log(addVisit(), addVisit());
const nextCount = (n) => n + 1;
console.log(nextCount(0), nextCount(0));1 2 1 1
const isAdult = (age) => age >= 19;
function check(input, want) {
const got = isAdult(input);
const ok = got === want;
console.log(input, ok ? '合格' : '不合格');
}
check(18, false);
check(19, true);
check(0, false);18 合格 19 合格 0 合格
📌 要点まとめ
- 関数は入力(引数)を受け取って処理し、結果を
returnで返す名前付きのコードである console.logは人に見せるだけで、ほかのコードが使うにはreturnしなければならない- 実引数が抜ければ
undefined、returnがなければundefined— エラーなしにNaNになりうる - アロー関数に波かっこを使うなら
returnを自分で書く - 一文で説明できる小さな純粋関数に分ければ、入力と期待値の表で試しやすい
🧪 コード実習
計算する関数は値を返さないと採点されません。画面に出すだけのコードを直す問題から、小さな関数を組み立てる問題まで、順に解いてみましょう。
コードはこのブラウザの中の隔離された場所でだけ実行され、サーバーには送られません。ネットワークには接続できず、2秒を超えると止まります。書き換えたコードはこのブラウザにだけ保存されます。Ctrl+Enter(⌘+Enter)で実行、Tabキーは空白2つ(Escの後のTabで次へ移動)。
JavaScriptが無効なので実行はできませんが、問題・最初のコード・自動チェックの内容・解答例はそのまま読めます。
1摂氏を華氏に
摂氏の温度 c を受け取り、華氏の温度を返す関数 cToF(c) を作ってください。公式は 華氏 = 摂氏 × 9 / 5 + 32 です。例: cToF(100) は212。
cToF(0)期待値32cToF(100)期待値212cToF(-40)期待値-40cToF(36.5)期待値97.7
💡 ヒント
return がないと、関数は undefined を返します。
解答例を見る
function cToF(c) {
return c * 9 / 5 + 32;
}2出力するだけの関数を直す
架空のネットショップの送料を求める関数 shippingFee(sum) は、合計 sum が50,000ウォン以上なら0、そうでなければ3000を返さなければなりません。最初のコードは値を画面に出すだけなので採点に失敗します。値を返すように直してください。
shippingFee(12000)期待値3000shippingFee(50000)期待値0shippingFee(49999)期待値3000shippingFee(80000)期待値0
💡 ヒント
console.log(値) を return 値 に変えれば大丈夫です。50,000は境界値で、「以上」なので無料です。
解答例を見る
function shippingFee(sum) {
if (sum >= 50000) {
return 0;
}
return 3000;
}3小さな関数を組み立てる
価格の配列 prices を受け取り、最終的な支払い金額を返す orderTotal(prices) を作ってください。合計に送料(合計50,000ウォン以上なら0ウォン、そうでなければ3,000ウォン)を足します。ただし空の配列なら注文がないので0を返します。最初のコードにある subtotal・shippingFee を活用してください。
orderTotal([20000,10000])期待値33000orderTotal([30000,20000])期待値50000orderTotal([])期待値0orderTotal([49999])期待値52999orderTotal([60000,5000])期待値65000
💡 ヒント
空の配列かどうかは prices.length === 0 で確かめます。その検査をいちばん前に置いてすぐに return すれば、下の計算は実行されません。
解答例を見る
function subtotal(prices) {
let sum = 0;
for (const p of prices) {
sum += p;
}
return sum;
}
const shippingFee = (sum) => (sum >= 50000 ? 0 : 3000);
function orderTotal(prices) {
if (prices.length === 0) {
return 0;
}
const sum = subtotal(prices);
return sum + shippingFee(sum);
}4範囲の中に収める(アロー関数)
数 x を min 以上 max 以下に収めて返すアロー関数 clamp を作ってください。x が min より小さければ min、max より大きければ max、その間なら x のままです。例: clamp(15, 0, 10) は10。(min は max より大きくないものとします。)
clamp(15, 0, 10)期待値10clamp(-3, 0, 10)期待値0clamp(7, 0, 10)期待値7clamp(0, 0, 10)期待値0clamp(10, 0, 10)期待値10
💡 ヒント
波かっこを使ったアロー関数なので、すべての分岐に return が必要です。Math.min と Math.max を重ねて一行で書く方法もあります。
解答例を見る
const clamp = (x, min, max) => {
if (x < min) return min;
if (x > max) return max;
return x;
};🤖 AIにはこう聞いてみましょう
コピーして [ ] の部分を自分の状況に書き換えて使います。答えはそのまま信じず、本文と比べて確かめましょう。
長いコードを関数に分けたいとき
下のJavaScriptのコードを「一つのことだけをする」小さな関数に分けてください。各関数の名前・引数・戻り値を表にまとめ、計算する関数は `console.log` を使わずに `return` するようにしてください。動作は変えずに、変わった点を行ごとに説明してください。コード: [貼り付け]
自分で作った関数を試すテスト表が欲しいとき
次の関数に渡すテストの入力と期待値を6つ、表にしてください。ふつうの場合2つ、境界値(0・空の値・基準と同じ値)3つ、おかしな入力1つとし、それぞれの期待値がなぜそうなるのか一行ずつ説明してください。関数の説明: [何をする関数か] コード: [貼り付け]
`return` と `console.log` がまぎらわしいとき
JavaScriptで `return` と `console.log` の違いがわかる、ごく短い例を3つ作ってください。どの例も実行結果は先に言わず、私が結果を予想して答えたら、合っているかどうかと理由を教えてください。
🧰 関連ツール
この講義で扱ったJSON・正規表現・テキストを、その場で確かめたり整えたりできるツールです。本物の個人情報やパスワードは貼り付けないでください。
- MDN Web Docs — JavaScriptガイド: 関数(Functions)
- MDN Web Docs — アロー関数式、return 文、デフォルト引数のリファレンス
- プログラミング入門書で扱われる、純粋関数と単体テストの一般的な考え方
学習目標をすべて達成できたら完了を押しましょう。
このブラウザでは保存できないため、この画面でのみ表示されます。