初めての関数定義:再利用可能なコードブロックを作る

初めての関数定義:再利用可能なコードブロックを作る(VSCODE画面)
目次

関数とは?(特定のタスクを実行するコードブロック)

関数の基本概念:プログラムの部品化と再利用性の本質
プログラミングにおける「関数(Function)」とは、ある作業や計算を行う命令をひとまとめにし、名前を付けた「コードブロック」のことです。ソースでも、関数を使うと「特定のタスクを実行するための再利用可能なコードブロック」を作れ、引数を受け取ったり値を返したりできると説明されています。
では、なぜ関数が必要なのでしょうか。Web開発やアプリ開発では、同じ処理を何度も書くのは非効率で、ミスが増える原因にもなります。たとえば2つの数値を足す処理をあちこちに書いていると、後で仕様変更が入ったときに、すべての場所を修正しなければなりません。しかしソースのように function add(a, b) { return a + b; } と一度作っておけば、add(3, 4) のように呼び出すだけで何度でも使えます。これは「DRY(Don’t Repeat Yourself)原則」と呼ばれ、関数はこの原則を実現するための最も基本的な道具です。
また関数は、コードを読みやすくする効果もあります。数百行の処理がずらっと並ぶより、fetchData や calculateScore のように役割が分かる名前の関数に分けておけば、「この部分は何をしているのか」が一目で分かります。ソースでは、関数内で処理が行われ、その結果が result 変数に代入される流れが示されていますが、これは関数が「入力(引数)を受け取り、処理(ロジック)を行い、出力(戻り値)を返す」という“ブラックボックス”として働くことを表しています。
JavaScriptはECMAScriptという標準仕様に基づいていますが、関数の考え方は初期から変わらず存在しています。一方で、書き方や機能はES2015(ES6)などの更新で進化してきました。初心者はまず「処理をまとめて名前を付ける」という関数の役割をしっかり理解することが、後の非同期処理やフレームワーク学習の土台になります。

関数の構文バリエーション:宣言、式、アロー関数

JavaScriptで関数を定義する方法は、主に「関数宣言(Function Declaration)」「関数式(Function Expression)」「アロー関数(Arrow Function)」の3つがあります。どれも似た用途で使えますが、書き方や挙動(特にthisやホイスティング)に違いがあります。
関数宣言:最も基本の書き方です。ソースのように function キーワードで、関数名・引数・処理内容を書きます。
function add(a, b) {
return a + b;
}
この形式の特徴は、ホイスティング(巻き上げ)です。定義より前に add(1, 2) と書いても動くことがあります。
アロー関数:ソースで紹介されている、より新しく短い書き方です。=>(矢印)を使って定義します。
const greet = (name) => {
return こんにちは、${name}さん!;
};
アロー関数は関数式を簡潔に書けるため、特にコールバック関数として使う場面で便利です。ソースの例ではテンプレートリテラル( )で name を埋め込み、挨拶文を返しています。アロー関数の特徴として、functionで作る関数と違い、独自のthisを持たない点があります。これはクラス設計などで重要ですが、最初は「短く書ける便利な記法」と捉えておけば十分です。
ソースにある通り、ES5とES6以降で書き方は変わりますが、現在はアロー関数が標準的に使われています。特にReactなどのフレームワークでは多用されるため、学習の早い段階で慣れておくと役立ちます。

データの受け渡し:引数と戻り値のメカニズム

関数が「再利用できる部品」になるには、外からデータを受け取り、結果を外へ返す仕組みが必要です。それが「引数(Parameters)」と「戻り値(Return Value)」です。
引数(入力):ソースの function add(a, b) では a と b が引数です。add(3, 4) と呼ぶと、関数の中では a=3、b=4 として処理されます。引数があるから、同じ add 関数で add(10, 20) や add(100, -5) のように違う計算ができます。アロー関数の (name) => { … } も同様で、greet(“太郎”) と呼べば name に “太郎” が入り、挨拶文が作られます。
戻り値(出力):関数の結果を呼び出し元へ返すのが return です。ソースでは return a + b; の結果が const result に入ります。もし return がない場合、関数は undefined を返します。戻り値があると、結果を別の計算に使ったり、他の関数の引数に渡したりできます(関数の合成)。
テンプレートリテラルとの連携:文字列を返すときは、ソースで解説されているテンプレートリテラルがよく使われます。”Hello ” + name + “!” のような結合よりも、${name} のように埋め込めて読みやすく、ミスも減ります。ソースの例でも、式を直接埋め込むなど、関数の出力を柔軟に作れることが示されています。

スコープと変数の生存期間:関数スコープとブロックスコープ

関数を作るときに避けて通れないのが「スコープ(変数の有効範囲)」です。変数は、どこで宣言したかによって参照できる範囲が決まります。ここを理解しないと、未定義になったり、意図せず上書きされたりするバグの原因になります。
グローバルスコープとローカルスコープ:ソースでは「ページ全体で使えるグローバル」と「限られた範囲で使えるローカル」があると説明されています。関数内で宣言した変数は関数スコープを持ち、関数の外からは参照できません。ソースの例では、scopeUse内で宣言した valGlobal1 はローカル変数として扱われ、外側の同名変数とは別物として動きます。これにより、変数名の衝突や意図しない上書きを防げます。
ブロックスコープとvar/let/const:昔はvarが主流でしたが、varは関数スコープしか持たず、ifやforのブロック内で宣言しても外から参照できてしまう問題がありました。これを解決したのがES6のletとconstです。ソースの通り、letはブロックスコープを持ち、ブロック外から触るとReferenceErrorになります。関数を作るときは、変数の影響範囲を小さくするため、基本はlet/constを使い、スコープを閉じるのが推奨されます。これにより、JavaScriptの「ゆるさ」を抑え、堅牢なコードを書けます。

クロージャ:状態を保持する関数の仕組みとカプセル化

「クロージャ(Closure)」は、関数と、その関数が定義された環境(レキシカルスコープ)をセットで扱う仕組みです。初心者には難しく感じますが、ソースでは「関数とその関数が定義された状態をセットにした特殊なオブジェクト」と説明されています。
状態の保持:通常、関数の中で作った変数は関数が終わると消えます。しかしクロージャを使うと、関数が終わった後も変数の値を保持できます。ソースの比較例では、通常の関数は呼ぶたびに初期化されますが、createTimerの例では var time = 10; が保持され、呼ぶたびに 9, 8, 7… と減っていきます。これは内側の関数が外側の変数timeを参照し続けるためです。
カプセル化:クロージャの大きなメリットは「外から直接触れさせない」ことです。ソースのHelloオブジェクトの例では、var name は外から直接触れませんが、getNameやsetNameのようなメソッド経由でだけ操作できます。これにより予期せぬ書き換えを防ぎ、安全な設計ができます。
ただしソースでも注意されている通り、クロージャは変数をメモリ上に残し続けるため、不要なデータを保持するとメモリリークの原因になります。大きなデータを意図せず抱え込まないよう注意が必要です。

コールバック関数と高階関数:関数を値として扱う

JavaScriptでは関数を「第一級オブジェクト」として扱えます。つまり、関数を変数に入れたり、引数として渡したり、戻り値として返したりできます。
コールバック関数:ある関数に引数として渡され、処理の途中や最後に呼び出される関数をコールバック関数と呼びます。ソースの例を見てみましょう。
function fetchData(callback) {
setTimeout(() => {
const data = “データ”;
callback(data);
}, 1000);
}
fetchDataはcallbackを受け取り、1秒後にcallback(data)を実行しています。これにより「データを取る」処理と、「取った後に何をするか(表示・保存など)」を分離できます。ソースのonloadイベント例でも、読み込み後の処理をコールバック(クロージャ)として渡しています。
高階関数:関数を引数に取ったり、戻り値として関数を返したりする関数を高階関数と呼びます。ソースのmakeOnLoadCallbackは、実行結果として新しい関数(クロージャ)を返しています。配列操作で使う map / filter / forEach(ソース)なども、コールバックを受け取る高階関数の一種です。これらを使いこなすと、ループ処理を短く書けるようになります。

非同期処理における関数:Promiseとasync/await

現代のJavaScript、とくにWeb開発では、データ取得やタイマーなど「非同期処理」が欠かせません。関数はこの非同期処理の制御でも中心になります。
非同期処理の必要性:JavaScriptはシングルスレッドなので、通信のような時間のかかる処理を同期でやると画面が固まります。これを避けるため、処理完了を待たずに次へ進む非同期処理が使われます。
Promise:コールバックを多用すると入れ子が深くなり「コールバック地獄」になりがちです。これを解決するため、ES6でPromiseが導入されました。ソースの通り new Promise((resolve, reject) => { … }) で作り、成功ならresolve、失敗ならrejectを呼びます。これにより.then()で処理をつなげられ、読みやすくなります。
async/await:さらにES2017でasync/awaitが追加され、非同期処理を同期処理のように書けるようになりました。関数にasyncを付けると自動でPromiseを返し、awaitを使うと結果が出るまで一時停止してから次へ進みます。
async function fetchData() {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
このように関数とasync/awaitを組み合わせると、複雑な非同期でも整理されたコードで書けます。Qiita APIを叩く例などは実務でもよくある形です。

オブジェクト指向と関数:メソッドとコンストラクタ

JavaScriptはプロトタイプベースのオブジェクト指向言語で、Javaのようなクラスベースとは違いますが、関数を使ってオブジェクト指向的な仕組みを作れます。
コンストラクタ関数:classが入る前は、関数でクラスのようなものを作っていました。ソースのStudent関数が例です。
var Student = function(name, id) {
this.name = name;
this.id = id;
};
これを new Student(…) で呼ぶと、新しいオブジェクト(インスタンス)が作られます。ここでの this は、そのインスタンス自身を指します。
メソッド:オブジェクトの中に入っている関数をメソッドと呼びます。ソースでは Student.prototype に getName や getFullData などを追加し、Studentから作られた全インスタンスで共有できるようにしています。メソッド内の this は、呼び出したオブジェクトを指します。ただしアロー関数でメソッドを書くとthisの挙動が変わるので注意が必要です。
このように、JavaScriptでは関数とプロトタイプを使って、データと処理をセットにしたオブジェクト指向の設計ができます。

DOM操作とイベントハンドラ:インタラクティブな動作

Webページに動きを付けるには、HTML要素(DOM)を操作します。このDOM操作とイベント処理でも関数が主役です。
イベントハンドラ:ボタンのクリックや入力などのイベントが起きたときに実行される関数をイベントハンドラ(イベントリスナー)と呼びます。ソースの例は次の通りです。
button.addEventListener(“click”, () => {
console.log(“ボタンがクリックされました!”);
});
ここではaddEventListenerの第2引数に関数を渡し、クリック時にブラウザがその関数を呼び出します。これがイベント駆動プログラミングの基本です。
DOM操作の関数化:DOM操作は要素取得・内容作成・挿入などが必要で、コード量が増えがちです。ソースでは insertAdjacentElement なども紹介されていますが、こうした処理を createListItem(text) のように関数にまとめておくと、呼び出すだけで済みます。document.getElementById や querySelector で要素を取る処理も、繰り返すなら関数化しておくと便利です。関数で複雑さを隠し、メインのロジックをすっきり保てます。

サーバーサイドJavaScript(Node.js)での関数活用

JavaScriptはブラウザだけでなく、Node.jsによりサーバー側でも動きます。ここでも関数はフル活用されます。
Webサーバーの作成:ソースのYouTube書き起こしでは、Node.jsでWebサーバーを作る流れが紹介されています。
const server = http.createServer((request, response) => {
// レスポンス処理
});
ここでもcreateServerの引数として、requestとresponseを受け取るコールバック関数を渡しています。アクセスがあるたびにこの関数が実行され、HTMLを返したりヘッダーを設定したりします。
モジュールとrequire:Node.jsではfsやhttpなどがモジュールとして用意され、require(‘http’)のように読み込んで使います。これらのモジュールも内部は多数の関数で構成されています。また、自作の関数を module.exports で外へ公開し、別ファイルから使うこともできます。こうして機能をファイル単位・関数単位で分割できるため、大規模開発でも管理しやすくなります。
フロントでもバックでも、JavaScriptを書くということは「関数を定義して、必要なタイミングで呼び出す」ことにほかなりません。今回学んだ関数の基礎(定義、スコープ、クロージャ、非同期、オブジェクト指向)は、環境が変わっても通用する普遍的なスキルです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次