変数

変数は、値に代表名を割り当てるデータ構造です。どのような種類のデータでも含めることができます。

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

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

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

    JavaScript で識別子の先頭に数値が許可されていた場合、数値のみで構成される識別子が許可され、数値として使用される数値と識別子として使用する数値の間に競合が生じます。

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

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

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

JavaScript の組み込みメソッドとプロパティで設定された例によれば、キャメルケース(「キャメルケース」としてもスタイル化)は、複数の単語で構成される識別子の非常に一般的な規則です。キャメルケースとは、スペースなしで読みやすくするために、最初の単語を除くすべての単語の最初の文字を大文字にする方法です。

let camelCasedIdentifier = true;

一部のプロジェクトでは、コンテキストやデータの性質に応じて他の命名規則を使用します。たとえば、クラスの最初の文字は通常大文字になるため、マルチワードのクラス名では一般に「大文字キャメルケース」またはパスカルケースと呼ばれるキャメルケースのバリアントが使用されます。

class MyClass {

}

識別子は、含まれるデータの性質を簡潔に記述し(たとえば、theNumberOfDaysInTheCurrentMonth よりも currentMonthDays の方が名前が適切)、ひと目ではっきりと読み取れる必要があります(originalValueval より優れています)。このモジュール全体で使用される myVariable 識別子は、分離された例のコンテキストでは機能しますが、含まれるデータに関する情報が得られないため、本番環境コードではまったく役に立ちません。

識別子は、含まれるデータを細かくしすぎないようにする必要があります。識別子の値は、そのデータに対するスクリプトの動作や、将来のメンテナンス担当者が行う決定によって変わる可能性があるためです。たとえば、元々 ID に miles が割り当てられていた変数を、プロジェクトの後半で km 単位の値に変更する必要が生じた場合、将来の混乱を避けるためにメンテナンス担当者はその変数の参照を変更する必要があります。これを防ぐには、代わりに distance を ID として使用します。

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

変数の宣言

JavaScript に識別子を認識させるには、変数の「宣言」と呼ばれるプロセスが複数あります。変数は、letconst、または 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

識別子と値の関連付けは一般に「バインディング」と呼ばれます。letvar、または 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

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

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

可変ホイスティング

変数と関数の宣言は、スコープの一番上にホイスティングされます。つまり、JavaScript インタープリタはスクリプト内の任意の時点で宣言された変数を処理し、スクリプトを実行する前に、それを包含するスコープの 1 行目に実質的に移動します。つまり、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 is notdefined」エラーとは異なります。JavaScript によって変数がホイスティングされているため、変数が指定されたスコープ内で作成されることが認識されます。ただし、値 undefined の宣言の前にその変数を使用できるようにするのではなく、インタープリタはエラーをスローします。let または const(または class)で宣言された変数は、包含ブロックの先頭からコード内の変数が宣言されている位置まで、「時間的デッドゾーン」(TDZ)に存在するとみなされます。

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

理解度をチェックする

識別子に使用できる文字の種類は何ですか。

文字
アンダースコア
数字

値を随時変更できる変数を宣言する場合、推奨される方法はどれですか。

する
const
var