レキシカルスコープとは?
レキシカルスコープ(Lexical Scope)は、変数がどのスコープに属するかを「コードの構造」や「定義された場所」に基づいて決定するものです。JavaScript、Python、Cなどの多くのプログラミング言語はこのスコープの仕組みを採用しています。関数がどこで「定義」されたかが重要であり、その関数が「呼び出される場所」によって変数の参照範囲が変わりません。
let x = 10;
function foo() {
console.log(x); // このxは、fooが定義された場所のスコープから参照される
}
function bar() {
let x = 20;
foo(); // ここで呼び出してもxは10のまま
}
bar(); // 10
上記のコードでは、foo
はbar
の中で呼び出されても、foo
が定義された場所のスコープ(グローバルスコープ)を参照します。bar
の中にx = 20
があっても、それは無視されます。これは、レキシカルスコープが「定義時のスコープ」を重視するためです。
ダイナミックスコープとは?
一方、ダイナミックスコープ(Dynamic Scope)は「実行時のスコープ」に基づいて変数を解決します。関数が呼び出された「場所」によって、そのスコープが決まります。したがって、ダイナミックスコープでは関数の呼び出し元が変わると、参照される変数も変わります。近年の主流の言語ではあまり使われていませんが、Lispや一部のシェルスクリプトでこの考え方が採用されています。
たとえば、JavaScriptがダイナミックスコープを採用していたとしたら、次のようになります。
let x = 10;
function foo() {
console.log(x); // このxは、呼び出し元のスコープから参照される
}
function bar() {
let x = 20;
foo(); // ダイナミックスコープだとxは20になる
}
bar(); // 20
この場合、foo
関数が呼び出される時点のスコープ(bar
のスコープ)を参照するため、x
は20
となります。つまり、ダイナミックスコープでは、関数の「呼び出し元」のスコープが参照されるのです。
レキシカルスコープ vs ダイナミックスコープ
レキシカルスコープ | ダイナミックスコープ | |
---|---|---|
スコープの決定 | 定義された場所に基づく | 呼び出し元の場所に基づく |
メリット | コードの予測可能性が高い | 実行時の状況に柔軟に対応できる |
デメリット | 柔軟性が低くなる場合がある | コードの挙動が予測しにくくなる |
レキシカルスコープの最大の利点は、コードを見ただけで変数の参照先がわかり、予測がしやすいことです。一方で、ダイナミックスコープは実行時の状況に応じて変数を解決できるため、柔軟性はありますが、逆にどの変数が参照されるかが分かりづらくなることが多いです。
なぜレキシカルスコープが一般的なのか?
レキシカルスコープが一般的な理由は、その予測可能性と安定性にあります。定義時のスコープが参照されるため、コードを読むだけで変数がどこから来るのか理解しやすく、バグを防ぎやすいからです。
一方で、ダイナミックスコープの柔軟性が求められる場面は、特殊なケースに限られるため、現代のプログラミング言語ではレキシカルスコープが主流となっています。