変数

変数は、値に代表的な名前を割り当てるデータ構造です。任意のデータを含めることができます。

変数名は識別子と呼ばれます。有効な識別子は、次のルールに従う必要があります。

  • 識別子には、Unicode の文字、ドル記号($)、アンダースコア文字(_)、数字(0 ~ 9)、一部の Unicode 文字を含めることができます。
  • パーサーは空白文字を使用して入力要素を区切るため、識別子に空白文字を含めることはできません。たとえば、myVariable ではなく変数 my Variable を呼び出そうとすると、パーサーは 2 つの識別子(myVariable)を検出し、構文エラー(「予期しないトークン: 識別子」)をスローします。
  • 識別子は、文字、アンダースコア(_)、ドル記号($)で始める必要があります。数字と識別子の混同を避けるため、数字で始めることはできません。

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    JavaScript で識別子の先頭に数字が使用可能になると、数字のみで構成される識別子が許可され、数字として使用される数字と識別子として使用される数字の間で競合が発生します。

    let 10 = 20
    
    10 + 5
    > ?
    
  • すでに構文的に意味のある「予約語」は、識別子として使用できません。

  • 識別子に特殊文字(! . , / \ + - * =)を含めることはできません。

以下は、識別子を作成するための厳格なルールではありませんが、コードの保守を容易にする業界のベスト プラクティスです。特定のプロジェクトに異なる標準がある場合は、整合性を確保するために、その標準に従ってください。

JavaScript の組み込みメソッドとプロパティの例に従い、複数の単語で構成される識別子には、キャメルケース(「camelCase」とも呼ばれます)が非常に一般的に使用されます。キャメルケースとは、最初の単語を除くすべての単語の最初の文字を大文字にして、スペースなしで読みやすくする方法です。

let camelCasedIdentifier = true;

プロジェクトによっては、コンテキストとデータの性質に応じて他の命名規則を使用しています。たとえば、クラスの最初の文字は通常大文字にするため、複数の単語で構成されるクラス名では、キャメルケースのバリエーション(アッパー キャメルケースまたはPascalケース)がよく使用されます。

class MyClass {

}

識別子は、含まれるデータの性質を簡潔に記述し(たとえば、currentMonthDaystheNumberOfDaysInTheCurrentMonth よりも良い名前です)、一目でわかりやすくする必要があります(originalValueval よりも優れています)。このモジュール全体で使用されている myVariable 識別子は、個別の例のコンテキストでは機能しますが、含まれるデータに関する情報を提供していないため、本番環境コードでは非常に役に立ちません。

識別子には、含まれるデータについて具体的すぎる名前を付けないでください。スクリプトがそのデータに対してどのように動作するか、または将来のメンテナンス担当者が下す決定によって、値が変更される可能性があるためです。たとえば、元々 ID miles が割り当てられた変数を、プロジェクトの後半でキロメートル単位の値に変更する必要がある場合、メンテナンス担当者は将来の混乱を避けるために、その変数への参照をすべて変更する必要があります。これを回避するには、代わりに distance を識別子として使用します。

JavaScript では、アンダースコア文字(_)で始まる識別子に特別な権限や意味は与えませんが、通常は、変数、メソッド、プロパティが「プライベート」であることを示すために使用されます。つまり、その変数、メソッド、プロパティは、それを含むオブジェクトのコンテキスト内でのみ使用することを目的としており、そのコンテキストの外部からアクセスまたは変更してはならないことを示します。これは他のプログラミング言語から引き継がれた規則であり、JavaScript のプライベート プロパティの追加より前のものでした。

変数の宣言

JavaScript に識別子を認識させる方法は複数あります。このプロセスは変数の「宣言」と呼ばれます。変数は、letconst、または var キーワードを使用して宣言します。

let myVariable;

いつでも変更できる変数を宣言するには、let または var を使用します。これらのキーワードは、文字列が値を含む可能性がある識別子であることを JavaScript インタープリタに伝えます。

最新のコードベースで作業する場合は、var ではなく let を使用します。var は最新のブラウザでも引き続き動作しますが、JavaScript の初期バージョンで定義された直感に反する動作があり、下位互換性を維持するために後で変更できません。let は、var の設計に関するいくつかの問題に対処するために ES6 で追加されました。

宣言された変数は、変数に値を割り当てることで初期化されます。値を変数に割り当てる、または再割り当てするには、単一の等号(=)を使用します。これは、宣言する同じステートメントの一部として行うことができます。

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

識別子と値の関連付けは、一般に「バインディング」と呼ばれます。letvarconst キーワードに続く構文は「バインディング リスト」と呼ばれ、カンマ区切りで複数の変数宣言を指定できます(セミコロンで終了)。これにより、次のコード スニペットは機能的に同じになります。

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

let(または var)で宣言された変数の値を変更する方法で、const で宣言された変数の値を変更しようとすると、型エラーが発生します。

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 アプリケーション全体で、すべてのブロックと関数内、ページ上の任意のスクリプトで使用できます。

これは望ましいデフォルトのように思えますが、アプリケーションの任意の部分がアクセスして変更できる変数は、不要なオーバーヘッドを追加したり、アプリケーション内の他の場所にある同じ ID の変数との競合を引き起こしたりする可能性があります。これは、サードパーティ ライブラリやユーザー アナリティクスなど、ページのレンダリングに関連するすべての 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

変数を明示的に宣言せずに値を割り当てる(つまり、varletconst を使用して変数を作成しない)と、関数またはブロック内で初期化された場合でも、変数はグローバル スコープに昇格します。このパターンを使用して作成された変数は、「暗黙的なグローバル」と呼ばれることもあります。

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

変数のホイスティング

変数と関数の宣言はスコープの先頭にホイスティングされます。つまり、JavaScript インタープリタはスクリプトの任意の位置で宣言された変数を処理し、スクリプトを実行する前に、その変数を囲むスコープの最初の行に移動します。つまり、var を使用して宣言された変数は、変数を宣言する前に参照してもエラーは発生しません。

hoistedVariable
> undefined

var hoistedVariable;

ホストされるのは変数の宣言のみで、初期化は行われないため、varletconst で明示的に宣言されていない変数はホイスティングされません。

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

前述のように、宣言されていても初期化されていない変数には undefined の値が割り当てられます。この動作は、ホイスティングされた変数宣言にも適用されますが、var を使用して宣言された変数宣言にのみ適用されます。

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

この直感に反する動作は、主に JavaScript の初期バージョンで行われた設計上の決定に起因しており、既存のサイトを破壊するリスクなしに変更することはできません。

letconst は、変数が作成される前にアクセスされたときにエラーをスローすることで、この動作に対処します。

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

このエラーは、宣言されていない変数にアクセスしようとしたときに発生する「hoistedVariable は定義されていません」というエラーとは異なります。JavaScript によって変数がホイスティングされているため、JavaScript は、変数が指定されたスコープ内で作成されることを認識しています。ただし、宣言前にその変数を undefined の値で使用できるようにする代わりに、インタープリタはエラーをスローします。let または const(または class)で宣言された変数は、囲むブロックの先頭から変数が宣言されているコードの位置までの「時間的デッドゾーン」(TDZ)に存在するといわれます。

時間的なデッドゾーンにより、作成者にとって let の動作が var よりも直感的になります。また、const の設計においても重要です。定数は変更できないため、スコープの最上部にホイスティングされ、暗黙的な値 undefined が指定された定数は、意味のある値で初期化できませんでした。

理解度を確認する

識別子の先頭に使用できる文字はどのようなものですか。

手紙
アンダースコア
1 桁

値をいつでも変更できる変数を宣言する場合、どの方法が推奨されますか。

let
const
var