スコープの話
自己紹介
Nobuhiro Nakashima @ombran JavaScript/Ruby/サンホラ/アニオタ 株式会社アラタナ エンジニア Miyazaki.js主催
スコープ
– by Wikipedia
“ある変数や関数が
特定の名前で参照される範囲のこと”
スコープ
スコープの種類
global scope プログラム「全体」から見えるスコープ
file scope プログラムを記述したファイルの内側でのみ参照できるスコープ
local scope ある関数やブロックの範囲内に限定されたスコープ
instance scope いわゆるカプセル化
class scope あるクラスの定義全体から参照できるスコープ
global scope プログラム「全体」から見えるスコープ
file scope プログラムを記述したファイルの内側でのみ参照できるスコープ
local scope ある関数やブロックの範囲内に限定されたスコープ
instance scope いわゆるカプセル化
class scope あるクラスの定義全体から参照できるスコープ
JavaScript
でのスコープ
スコープの例
var scope = "Global";
function getValue() { console.log(scope); // > undefined var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" (ローカル変数を参照)
console.log(scope); // > "Global" (グローバル変数を参照)
var scope = "Global";
function getValue() { console.log(scope); // > undefined var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" (ローカル変数を参照)
console.log(scope); // > "Global" (グローバル変数を参照)
global scope
var scope = "Global";
function getValue() { console.log(scope); // > undefined var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" (ローカル変数を参照)
console.log(scope); // > "Global" (グローバル変数を参照)
local scope
スコープの話の前に 変数の前のやつを説明します
varについて
varなし→必ずグローバル
varあり→スコープ内変数
varは絶対付けること
スコープをもうちょっと深く
global scope
• functionの外で宣言された変数・関数
• varなしで宣言された変数
var scope = "Global";
function getValue() { console.log(scope); // > “Global” scope = "Global2"; return scope; }
console.log(getValue()); // > "Global2" console.log(scope); // > "Global2"
functionの外で宣言
function getValue() { scope = "Global2"; return scope; }
console.log(getValue()); // > "Global2" console.log(scope); // > "Global2"
varなしで宣言
local scope
• functionの中で宣言された変数・関数
• functionの引数で宣言された変数
var scope = "Global";
function getValue() { console.log(scope); // > undefined var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" console.log(scope); // > "Global"
functionの中で宣言
var scope = "Global";
function getValue(arg1) { console.log(arg1); // > “Global” arg1 = "Local"; return arg1; }
console.log(getValue(scope)); // > "Local" console.log(scope); // > "Global"
functionの引数で宣言
なぜこういう挙動をするのか
スコープチェーン
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
ここの変数の値を探すルール
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
Cはこのスコープで見つかる
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
Bはこのスコープで見つかる
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
Aはこのスコープで見つかる
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
変数の 検索範囲が徐々に広がっている
これが スコープチェーン
var scope = "Global";
function getValue() { console.log(scope); var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" console.log(scope); // > "Global"
さっきのやつ
この時点で同一スコープを探す
var scope = "Global";
function getValue() { console.log(scope); var scope = "Local"; return scope; }
console.log(getValue()); // > "Local" console.log(scope); // > "Global"
さっきのやつ
この時点で同一スコープを探す
いた!!
なぜundefined?
var scope = "Global";
function getValue() { var scope; console.log(scope); // > undefined scope = "Local"; return scope; }
console.log(getValue()); // > "Local" console.log(scope); // > "Global"
こういうイメージ
だから変数は最初に 全部書きましょう
スコープチェーン による強力な機能
の前に ちょっと最新の話
ちなみに Javaなどにある
ブロックスコープですが
var sum = 0;
for (var i = 0; i < 10; i++) { sum += i; }
console.log(sum); console.log(i);
ブロックスコープ
var sum = 0;
for (var i = 0; i < 10; i++) { sum += i; }
console.log(sum); // > 45 console.log(i); // > ??
ブロックスコープ
var sum = 0;
for (var i = 0; i < 10; i++) { sum += i; }
console.log(sum); // > 45 console.log(i); // > ReferenceError 10
ブロックスコープ
var sum = 0;
for (var i = 0; i < 10; i++) { sum += i; }
console.log(sum); // > 45 console.log(i); // > ReferenceError 10
ブロックスコープ
ECMAScript6の新機能
letでできるよ
var sum = 0;
for (let i = 0; i < 10; i++) { sum += i; }
console.log(sum); // > 45 console.log(i); // > ReferenceError
ブロックスコープ
戻ります
スコープチェーン による強力な機能
クロージャ
– by Wikipedia
“引数以外の変数を実行時の環境ではなく、 自身が定義された環境(静的スコープ)において解決することを特徴とする。”
クロージャ
var a = “GlobalA”; var b = “GlobalB”;
function func1() { var b = “Func1B”;
function func2() { var c = “Func2C”;
console.log(c); // > “Func2C” console.log(b); // > “Func1B” console.log(a); // > “GlobalA” } func2(); } func1();
さっきのも クロージャ
クロージャの 実践例
function counter() { var count = 0;
return function() { count = count + 1; return count; } }
var cnt = counter(); console.log(cnt()); // > 1 console.log(cnt()); // > 2 console.log(cnt()); // > 3
変数の 永続化
function counter() { var count = 0;
return function() { count = count + 1; return count; } }
var cnt = counter(); console.log(cnt()); // > 1 console.log(cnt()); // > 2 console.log(cnt()); // > 3
変数の 永続化
ここで変数が束縛される
function counter() { var count = 0;
return function() { count = count + 1; return count; } }
var cnt = counter(); console.log(cnt()); // > 1 console.log(cnt()); // > 2 console.log(cnt()); // > 3
変数の 永続化
束縛されたままなので 値がインクリメントされる
即時関数
function helloWorld() { alert("Hello, World!"); } helloWorld();
普通の関数定義と実行
(function helloWorld() { alert("Hello, World!"); })();
即時関数
定義後、即実行
メリット
グローバルスコープを 汚さない
(function helloWorld() { alert("Hello, World!"); })();
helloWorld(); // > エラー
即時関数
ということは 関数名もいらない
(function() { alert("Hello, World!"); })();
即時関数
無名関数
どういう時に使うか
(function() { var hoge = 1; function fuga() { console.log(hoge); } fuga(); })();
ファイル内の全コードを囲む
なにがうれしい?
グローバルスコープを 汚さない
同一ページで 複数JSファイルを 読み込んでも
他のJSを壊さない
(function() { // ここに自分の
//JavaScriptコードを書く
})();
(function() { // ここに自分の
//JavaScriptコードを書く
})();
マナーとして覚えてください
fin