備忘録的プログラミングリファレンス

スコープ(変数の参照範囲)

 スコープ(変数の参照範囲)とは、変数の取得や変更といった変数の参照ができる範囲のことです。
 変数には宣言した箇所によって参照できる範囲が変わります。

let a = 10;

{
	let b = 100;

	console.log( 'a = ' + a );
	console.log( 'b = ' + b );
}

console.log( 'a = ' + a );
console.log( 'b = ' + b );	// エラーが起きる

 上記の場合、最後の b の参照console.log( 'b = ' + b );はエラーが起きます。
 b は {} のブロック内のみで参照できるからです。

 詳しくは以下のスコープについてを参照してください。

ページ内 Index

スコープについて

 スコープとは、変数の取得や変更といった変数の参照ができる範囲のことです。
 変数には宣言した箇所によって参照できる範囲が変わります。

 例えば以下のように {} 内で宣言した変数 b と予め宣言した a という変数があります。

let a = 10;

{
	let b = 100;

	console.log( 'a = ' + a );
	console.log( 'b = ' + b );
}

console.log( 'a = ' + a );
console.log( 'b = ' + b );

 実行すると以下のようになります。

> a = 10
> b = 100
> b = 10
> Uncaught ReferenceError: b is not defined

 {} はプログラムコード上ではブロックと呼ばれ、変数の参照範囲を決めます。
 上記の例では、 b という変数がブロック {} の中で宣言されており、そのブロックより外で b の値を参照しようしてエラーが発生しています。

 ブロック {} は、if や for といったフロー制御構文でも使用されます。フロー制御構文においても {} はブロックの意味です。

 a はブロック内でも、外でも参照することができます。
 a はプログラムコードにおける階層の元で変数として宣言されています。このような階層の根元で宣言された変数をグローバル変数といいます。
 グローバル変数はブロック {} 内でも関数内でもその変数を参照することができます。

 グローバル変数はプログラムコードが大きくなるとその内容が把握しにくくなります。チームといった複数でプログラムを作成する時はグローバル変数は予めその用途と内容を決めておいた方が無難です。

Example

 以下は実際に上記の例がどのようになるかを確かめるための例です。以下の確認ボタンをクリックするとスクリプトを実行します。

同じ変数宣言

 JavaScript でブロックの外で宣言された変数をブロックの中で再宣言した場合の解説です。

 確認ボタンをクリックして以下の例を実行してみてください。

 ブロック内で同じ変数名 name を宣言していますが、ブロックの外では元に戻っています。

 これはブロック内での変数宣言は外での変数とは別としてで設定される機能によるものです。
 同じ変数名で宣言するとブロック内で一時的に変数が設定され、ブロックを出ると開放されます。

 ブロックの外と中で同じ変数名を使用するような場合は外で宣言された値がブロック内では参照できなくなります。この例ではブロック内で外で定義された値 "Jimmy" は参照することができません。

 コード途中のブロックの外と中で同じ変数宣言をすることはあまりないと思います。ここでは興味本位で確かめてみました。
 ただし、関数においては呼び出し元と同じ変数名を使用する場合があります。関数内での変数と呼び出し元での変数は別物という認識があるためです。

関数においける変数のスコープ

 関数においての変数の扱いはスコープに影響されます。
 関数の中で扱われる変数は関数の中で完結するように注意します。

 例えば以下のように変数を宣言し、get_Name() 関数で name を取得する場合を考えてみましょう。

let name = "Jimmy";

function get_Name(){
	return( name );
}

console.log( get_Name() );

 この例では常に get_Name() 関数を呼び出したら答えはJimmyを期待します。
 しかし、もしもどこかで name 変数の値を変更したら期待通りにはなりません。

 以下の例で確かめてみてください。

Example

 確認ボタンをクリックするとスクリプトを実行します。

 コードの途中で name の値を変更しています。この変更が把握できない状態で変更されたらデバグすることが困難になることでしょう。

 関数内で扱う変数は関数以内で完結するするようにするべきです。
 そのために、以下の例のように関数内で扱う変数を引数として渡す方法があります。

function get_Name( name ){
	return( name );
}

console.log( get_Name( "Jimmy" ) );
console.log( get_Name( "Tom" ) );

 関数に引数として渡せば期待された答えのみが返ってきます。

オブジェクトとスコープ

 オブジェクトを引数として関数に渡すこともできます。

let jimmy = {
	name : "Jimmy";
}

function get_Name( obj ){
	return( obj.name );
}

console.log( get_Name( jimmy ) );

 上記の例は関数にオブジェクトを渡すという方法です。しかし、オブジェクトを1つずつ作成することは非効率です。

 以下の例はクラス宣言をして、そのクラスを元にオブジェクトの配列を作成しています。

class Class_Student {
	constructor( name ) {
		this.name = name;
	}

	get_Name(){
		return( this.name );
	}
}

let students = [];
students.push( new Class_Student( 'Jimmy' ) );
students.push( new Class_Student( 'Tom' ) );

console.log( students[0].get_Name() );
console.log( students[1].get_Name() );

 オブジェクトごとに扱うため、途中で変数が期待をしない値に変えられたりしませんし、引数で参照する変数を指定していますのでそれ以外は影響を受けません。

Example