変数は、値に代表名を割り当てるデータ構造です。どのような種類のデータでも含めることができます。
変数の名前は識別子と呼ばれます。有効な識別子は次のルールに従う必要があります。
- 識別子には、Unicode 文字、ドル記号($)、アンダースコア文字(_)、数字(0 ~ 9)のほか、一部の Unicode 文字を含めることができます。
- パーサーは入力要素を空白文字で区切るため、識別子に空白文字を含めることはできません。たとえば、
myVariable
ではなく変数my Variable
を呼び出そうとすると、パーサーは 2 つの識別子(my
とVariable
)を確認し、構文エラー(「予期しないトークン: 識別子」)をスローします。 識別子は、英字、アンダースコア(
_
)、ドル記号($
)のいずれかで始まる必要があります。数字と識別子を混同しないよう、識別子を数字で始めることはできません。let 1a = true; > Uncaught SyntaxError: Invalid or unexpected token
JavaScript で識別子の先頭に数値が許可されていた場合、数値のみで構成される識別子が許可され、数値として使用される数値と識別子として使用する数値の間に競合が生じます。
let 10 = 20 10 + 5 > ?
すでに構文的に意味がある「予約語」を識別子として使用することはできません。
識別子に特殊文字(
! . , / \ + - * =
)を含めることはできません。
以下は、ID を作成するための厳格なルールではありませんが、コードの保守を容易にする業界のベスト プラクティスです。特定のプロジェクトに異なる標準がある場合は、代わりにそれに従って一貫性を確保してください。
JavaScript の組み込みメソッドとプロパティで設定された例によれば、キャメルケース(「キャメルケース」としてもスタイル化)は、複数の単語で構成される識別子の非常に一般的な規則です。キャメルケースとは、スペースなしで読みやすくするために、最初の単語を除くすべての単語の最初の文字を大文字にする方法です。
let camelCasedIdentifier = true;
一部のプロジェクトでは、コンテキストやデータの性質に応じて他の命名規則を使用します。たとえば、クラスの最初の文字は通常大文字になるため、マルチワードのクラス名では一般に「大文字キャメルケース」またはパスカルケースと呼ばれるキャメルケースのバリアントが使用されます。
class MyClass {
}
識別子は、含まれるデータの性質を簡潔に記述し(たとえば、theNumberOfDaysInTheCurrentMonth
よりも currentMonthDays
の方が名前が適切)、ひと目ではっきりと読み取れる必要があります(originalValue
は val
より優れています)。このモジュール全体で使用される myVariable
識別子は、分離された例のコンテキストでは機能しますが、含まれるデータに関する情報が得られないため、本番環境コードではまったく役に立ちません。
識別子は、含まれるデータを細かくしすぎないようにする必要があります。識別子の値は、そのデータに対するスクリプトの動作や、将来のメンテナンス担当者が行う決定によって変わる可能性があるためです。たとえば、元々 ID に miles
が割り当てられていた変数を、プロジェクトの後半で km 単位の値に変更する必要が生じた場合、将来の混乱を避けるためにメンテナンス担当者はその変数の参照を変更する必要があります。これを防ぐには、代わりに distance
を ID として使用します。
JavaScript では、アンダースコア文字(_
)で始まる識別子に特別な権限や意味は付与されませんが、通常は、変数、メソッド、プロパティが「非公開」であることを示すために使用されます。つまり、変数、メソッド、プロパティは、それを含むオブジェクトのコンテキスト内での使用のみを目的としており、そのコンテキスト以外でアクセスまたは変更すべきではありません。これは他のプログラミング言語から引き継いだ規則であり、JavaScript のプライベート プロパティが追加される前から存在しています。
変数の宣言
JavaScript に識別子を認識させるには、変数の「宣言」と呼ばれるプロセスが複数あります。変数は、let
、const
、または var
キーワードを使用して宣言します。
let myVariable;
let
または var
を使用して、いつでも変更できる変数を宣言します。これらのキーワードにより、文字列が値を含む可能性のある識別子であることが JavaScript インタープリタに伝えられます。
最新のコードベースで作業する場合は、var
ではなく let
を使用します。var
は最新のブラウザで引き続き機能しますが、初期バージョンの JavaScript で定義されていた、直感的でない動作もいくつかあり、下位互換性を維持するために後で変更することはできません。var
の設計に関するいくつかの問題に対処するために、ES6 で let
が追加されました。
宣言された変数は、変数に値を割り当てることで初期化されます。変数に値を代入または再代入するには、1 つの等号(=
)を使用します。これは、それを宣言するのと同じステートメントの一部として行うことができます。
let myVariable = 5;
myVariable + myVariable
> 10
let
(または var
)を使用して変数をすぐに初期化せずに宣言することもできます。その場合、コードで値が割り当てられるまで、変数の初期値は undefined
になります。
let myVariable;
myVariable;
> undefined
myVariable = 5;
myVariable + myVariable
> 10
値が undefined
の変数は、識別子がまだ宣言されていない未定義の変数とは異なります。宣言していない変数を参照すると、エラーが発生します。
myVariable
> Uncaught ReferenceError: myVariable is not defined
let myVariable;
myVariable
> undefined
識別子と値の関連付けは一般に「バインディング」と呼ばれます。let
、var
、または const
キーワードの後に続く構文は「バインディング リスト」と呼ばれ、複数の変数宣言(想定されるセミコロンで終わる)をカンマ区切りで指定できます。これにより、次のコード スニペットは機能的に同一になります。
let firstVariable,
secondVariable,
thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;
JavaScript では変数の存在がすでに認識されているため、変数の値を再代入しても let
(または var
)は使用されません。
let myVariable = true;
myVariable
> true
myVariable = false;
myVariable
> false
既存の値に基づいて、変数に新しい値を再代入できます。
let myVariable = 10;
myVariable
> 10
myVariable = myVariable * myVariable;
myVariable
> 100
本番環境で let
を使用して変数を再宣言しようとすると、構文エラーが発生します。
let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable
ブラウザのデベロッパー ツールでは、let
(および class
)の再宣言に関する制限が緩やかであるため、デベロッパー コンソールで同じエラーが表示されない可能性があります。
従来のブラウザの互換性を維持するため、var
ではどのようなコンテキストでもエラーなしで不要な再宣言が許可されます。
var myVariable = true;
var myVariable = false;
myVariable\
> false
const
const
キーワードを使用して定数を宣言します。これは、すぐに初期化する必要があり、変更はできません。定数の識別子は、let
(および var
)を使用して宣言された変数と同じルールに従います。
const myConstant = true;
myConstant
> true
定数は、すぐに値を割り当てずに宣言することはできません。定数は作成後に再割り当てできないため、初期化されていない定数は永続的に undefined
のままになります。初期化せずに定数を宣言しようとすると、構文エラーが発生します。
const myConstant;
Uncaught SyntaxError: missing = in const declaration
const
で宣言された変数の値を、let
(または var
)で宣言された変数の値を変更しようとすると、型エラーが発生します。
const myConstant = true;
myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'
ただし、オブジェクトに定数が関連付けられている場合は、そのオブジェクトのプロパティを変更できます。
const constantObject = { "firstvalue" : true };
constantObject
> Object { firstvalue: true }
constantObject.secondvalue = false;
constantObject
> Object { firstvalue: true, secondvalue: false }
オブジェクトを含む定数は、変更可能なデータ値への不変の参照です。定数自体は変更できませんが、参照先オブジェクトのプロパティは変更、追加、削除できます。
const constantObject = { "firstvalue" : true };
constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'
変数の再代入が不要な場合は、変数を定数にすることをおすすめします。const
を使用すると、開発チームまたはプロジェクトの将来の管理者がその値を変更しないように指示できます。これは、変数の使用方法に関するコードの前提(たとえば、変数は期待されるデータ型に対して評価されるなど)に反することを防ぐためです。
変数のスコープ
変数のスコープは、その変数を使用できるスクリプトの一部です。変数のスコープ外では、変数は定義されません。undefined
値を含む識別子としてではなく、宣言されていない場合と同様です。
変数の宣言に使用するキーワードと、変数を定義するコンテキストに応じて、変数のスコープを、ブロック ステートメント(ブロック スコープ)、個々の関数(関数スコープ)、または JavaScript アプリケーション全体(グローバル スコープ)に設定できます。
ブロック スコープ
let
または const
を使用して宣言した変数のスコープは、最も近いブロック ステートメントです。つまり、そのブロック内でのみ変数にアクセスできます。含まれているブロックの外部にあるブロック スコープ変数にアクセスしようとすると、存在しない変数にアクセスしようとしたのと同じエラーが発生します。
{
let scopedVariable = true;
console.log( scopedVariable );
}
> true
scopedVariable
> ReferenceError: scopedVariable is not defined
JavaScript に関する限り、ブロック スコープ変数は、それを含むブロックの外部には存在しません。たとえば、ブロック内で定数を宣言し、そのブロックの外部で同じ識別子を使用する別の定数を宣言できます。
{
const myConstant = false;
}
const myConstant = true;
scopedConstant;
> true
宣言された変数は親ブロックに拡張できませんが、すべての子孫ブロックで使用できます。
{
let scopedVariable = true;
{
console.log( scopedVariable );
}
}
> true
宣言された変数の値は、子孫ブロック内から変更できます。
{
let scopedVariable = false;
{
scopedVariable = true;
}
console.log( scopedVariable );
}
> true
新しい変数は、親ブロック内の変数と同じ識別子を使用している場合でも、子孫ブロック内でエラーなしで let
または const
で初期化できます。
{
let scopedVariable = false;
{
let scopedVariable = true;
}
console.log( scopedVariable );
}
> false
関数のスコープ
var
を使用して宣言された変数のスコープは、最も近い関数(またはクラス内の静的初期化ブロック)に設定されます。
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
これは、関数が呼び出された後にも当てはまります。関数の実行中に変数が初期化されても、その変数は関数のスコープ外では使用できません。
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
myFunction();
> true
scopedVariable;
> ReferenceError: scopedVariable is not defined
グローバル スコープ
グローバル変数は、JavaScript アプリケーション全体(すべてのブロックや関数内、ページ上のすべてのスクリプト内)で使用できます。
これは望ましいデフォルトのように見えますが、アプリケーションの任意の部分がアクセスして変更できる変数によって、不要なオーバーヘッドが増加したり、同じ識別子を持つアプリケーション内の他の場所にある変数と衝突したりする可能性があります。これは、サードパーティのライブラリやユーザー分析など、ページのレンダリングに関連するすべての JavaScript に適用されます。したがって、可能な限りグローバル スコープの汚染を避けることをおすすめします。
親関数の外部で var
を使用して宣言された変数、または親ブロックの外部で let
または const
を使用して宣言された変数は、グローバルです。
var functionGlobal = true; // Global
let blockGlobal = true; // Global
{
console.log( blockGlobal );
console.log( functionGlobal );
}
> true
> true
(function() {
console.log( blockGlobal );
console.log( functionGlobal );
}());
> true
> true
明示的に宣言せずに(つまり、var
、let
、または const
を使用して作成しない)変数に値を割り当てると、関数またはブロック内で初期化された場合でも、変数はグローバル スコープに昇格します。このパターンを使用して作成された変数は、「暗黙のグローバル」と呼ばれることもあります。
function myFunction() {
globalVariable = "global";
return globalVariable
}
myFunction()\
> "global"
globalVariable\
> "global"
可変ホイスティング
変数と関数の宣言は、スコープの一番上にホイスティングされます。つまり、JavaScript インタープリタはスクリプト内の任意の時点で宣言された変数を処理し、スクリプトを実行する前に、それを包含するスコープの 1 行目に実質的に移動します。つまり、var
を使用して宣言された変数は、その変数が宣言される前にエラーを発生させることなく参照できます。
hoistedVariable
> undefined
var hoistedVariable;
変数宣言のみがホストされ、初期化はホストされないため、var
、let
、const
で明示的に宣言されていない変数はホイスティングされません。
unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined
unhoistedVariable = true;
前述のとおり、宣言されているが初期化されていない変数には、undefined
の値が割り当てられます。この動作は、ホイスティングされた変数宣言にも適用されますが、var
を使用して宣言された宣言にのみ適用されます。
hoistedVariable
> undefined
var hoistedVariable = 2 + 2;
hoistedVariable\
> 4
この直感的でない動作は主に、初期バージョンの JavaScript で行われた設計上の決定事項からの逸脱によるものであり、既存のサイトに影響を及ぼすリスクを伴わない変更はできません。
let
と const
は、作成前に変数にアクセスしたときにエラーをスローすることで、この動作に対処します。
{
hoistedVariable;
let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization
このエラーは、宣言されていない変数にアクセスしようとしたときに想定される「hoistedVariable is notdefined」エラーとは異なります。JavaScript によって変数がホイスティングされているため、変数が指定されたスコープ内で作成されることが認識されます。ただし、値 undefined
の宣言の前にその変数を使用できるようにするのではなく、インタープリタはエラーをスローします。let
または const
(または class
)で宣言された変数は、包含ブロックの先頭からコード内の変数が宣言されている位置まで、「時間的デッドゾーン」(TDZ)に存在するとみなされます。
作成者にとって、時間的なデッドゾーンにより、let
の動作は var
よりも直感的になります。また、これは const
の設計にとっても重要です。定数は変更できないため、スコープの一番上にホイスティングされ、暗黙的な値 undefined
が指定された定数を、意味のある値で初期化することはできませんでした。
理解度をチェックする
識別子に使用できる文字の種類は何ですか。
値を随時変更できる変数を宣言する場合、推奨される方法はどれですか。