例1:関数宣言のホイスティング(復習)
console.log(foo()); // "I'm foo"
function foo() {
return "I'm foo";
}
JavaScript説明:function foo はホイスティングされる → 呼び出しが先でも動く。
例2:関数式 (const) はホイスティングしない
try {
console.log(bar()); // ReferenceError または TypeError(実行環境次第)
} catch (e) {
console.log('エラー:', e.message);
}
const bar = function() {
return "I'm bar";
};
JavaScript説明:bar は const に代入される「値」。代入前は使えない。
例3:var と巻き上げ(挙動が微妙)
console.log(baz); // undefined(宣言は巻き上げられるが、値は未初期化)
try {
console.log(baz()); // TypeError: baz is not a function
} catch (e) {
console.log('エラー:', e.message);
}
var baz = function() { return 'baz'; };
JavaScript説明:var 宣言は巻き上げられて undefined になるので、関数としては使えない。
例4:アロー関数と関数式
// NG
try {
console.log(arrow(2));
} catch (e) {
console.log('エラー:', e.message); // arrow is not defined / cannot access before initialization
}
const arrow = (n) => n * 2;
console.log(arrow(2)); // 4
JavaScript説明:アロー関数も関数式なので定義より前に呼べない。
例5:HTMLで <script> を分けたときの実例
(ファイルではなく1つのHTMLで試してみて)
<!-- head側 -->
<script>
init(); // この行が先に実行される → error になる場合がある
</script>
<script>
function init() {
console.log('init() 実行');
}
</script>
HTML修正版(安全パターン):
<body>
<button id="btn">押して</button>
<script>
function init() {
document.getElementById('btn').addEventListener('click', () => {
show();
});
}
function show() {
alert('押されたよ!');
}
// DOMが準備できたら init を呼ぶ
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
HTML説明:DOMContentLoaded を使うと、DOM要素が無いタイミングでエラーになるのを防げる。
例6:ネストした関数(スコープ)とクロージャ
function counterFactory() {
let count = 0;
return function() {
count += 1;
return count;
};
}
const counter = counterFactory();
console.log(counter()); // 1
console.log(counter()); // 2
JavaScript説明:内側の関数が外側の count を覚えている(クロージャ)。外部から直接 count は見えない。
例7:内部関数を外に「公開」する(Revealing Module Pattern)
const myModule = (function() {
let secret = 'shh';
function privateFn() { return 'private'; }
function publicFn() { return `public + ${privateFn()}`; }
return { publicFn }; // private は外に出さない
})();
console.log(myModule.publicFn()); // "public + private"
console.log(myModule.privateFn); // undefined
JavaScript説明:モジュール内のヘルパーを隠して安全に公開できる。
例8:よくあるミス — 関数を返す時の注意
function makeGreeter(name) {
// NG: 関数を返す時に () を付けると即時実行される
// return function() { console.log('Hi ' + name); }(); // これはダメ
// 正しい:関数そのものを返す
return function() { console.log('Hi ' + name); };
}
const greeter = makeGreeter('Ken');
greeter(); // "Hi Ken"
JavaScript説明:返すべきは「関数オブジェクト」そのもの。() を付けると呼んでしまう。
例9:イベントハンドラを後で定義するパターン(安全)
<button id="btn">Click</button>
<script>
// 関数宣言はボタンのクリック時に呼ばれるので、スクリプト内のどこにあってもOK
document.getElementById('btn').addEventListener('click', handleClick);
function handleClick() {
alert('clicked');
}
</script>
HTML説明:イベント登録は DOMがあることが前提。スクリプト位置に注意(body末尾かDOMContentLoadedを推奨)。
練習問題(手を動かそう)
- 次を実行して何が出る?理由も書いてみて。
console.log(x);
var x = 5;
console.log(x);
JavaScript- 次のコードをどう修正すると
Hello Aliceを表示する?
console.log(greet('Alice'));
const greet = name => 'Hello ' + name;
JavaScriptouterの中で定義したinnerを外から使いたい。ふたつの方法を書いてみて(ヒント:返す or グローバルに代入)。
解答(簡潔)
undefined(最初) →5(2回目)。varは宣言だけ巻き上げられる。greetをconstから先に定義する、またはfunction greet(name){...}と宣言に変える。- (A)
return inner;で関数を返す。 (B)window.inner = inner;のようにグローバルに代入(ただし推奨されない)。
