変数
変数の宣言方法
宣言方法はvar, let, constの3つ。
var
- 関数スコープの変数を宣言
- forやifなどのブロック
{}
でスコープを作らない
以下のコードでは i
, x
がブロック内で宣言されているが、ブロックの外から参照できる。
(() => {
for (var i = 0; i < 3; i++) { ... }
console.log(i); // 3
if (true) { var x = 100; }
console.log(x); // 100
})();
内部的には次のように解釈される。
(() => {
var i, x;
for (i = 0; i < 3; i++) { ... }
console.log(i);
if (true) { x = 100; }
console.log(x);
})();
let
- ブロックスコープの変数を宣言
(() => {
for (let i = 0; i < 3; i++) { 1 }
console.log(i); // ReferenceError: i is not defined
})();
if (true) { let x = 100; }
console.log(x); // ReferenceError: x is not defined
const
- ブロックスコープの定数を宣言
- 一度定義したら再代入できない
const foo = 'foo';
foo = 'bar'; // TypeError: Assignment to constant variable
変数の巻き上げ (hoisting)
代表的ハマりポイント!
変数をvarで宣言するとき、宣言より上で参照してもエラーにならない。
var foo = 1;
(function () {
console.log(foo); // undefined
var foo = 2;
console.log(foo); // 2
})();
内部的には次のように解釈されている。
var foo = 1;
(function () {
var foo; // 宣言を関数の先頭に巻き上げる
alert(foo); // 代入はまだなので undefined
foo = 2;
alert(foo);
})();
letやconstで宣言した変数は、宣言より前に触ろうとするとエラーが出る。
let foo = 1;
(function () {
console.log(foo); // ReferenceError: foo is not defined
let foo = 2;
console.log(foo); // 実行されない
})();
varとlet, constの使い分け
- 環境が許せばlet, constを使おう
- 最新のブラウザのみ対応すればよいとか
- Babel, TypeScriptが使えるとか
- 上記以外の環境ではvarで我慢
- ハマりやすいので注意
クロージャ
- 変数は基本的に関数スコープ
- 関数オブジェクト生成時に環境がつくられる
- 値を関数の中に閉じ込めることができる
クロージャでつくったカウンター。
function createCounter () {
var i = 0;
return function () {
return ++i;
};
};
var counter1 = createCounter();
var counter2 = createCounter();
alert(counter1()); //=> 1
alert(counter1()); //=> 2
alert(counter2()); //=> 1
alert(counter2()); //=> 2
privateでつくる。
function defineAdd (i) {
return function(v) {
return i + v;
};
};
var add1 = defineAdd(1);
var add2 = defineAdd(2);
alert(add1(1)); //=> 2
alert(add2(1)); //=> 3
alert(defineAdd(1)(2)); //=> 3