◆JavaScriptとは?
JavaScriptはWEBブラウザの中で動くプログラミング言語です。WEBサイトで操作をしたときに表示が書き換わったり、WEBサイトのサーバーと通信してデータを取得したりと現在のWEBサイトには欠かせないプログラミング言語です。このようなJavaScriptを活用してアプリケーションのように操作できるWEBサイトをWEBアプリとも言います。
JavaScriptはWEBブラウザだけではなく、Node.jsというサーバー側のアプリケーションを作る仕組みでも利用されています。 また、デスクトップアプリやスマートフォンアプリ、IoT(Internet of Things)デバイスでもJavaScriptを使って動かせるものがあります。 このように、JavaScriptはかなり幅広い環境で動いているプログラミング言語で、さまざまな種類のアプリケーションを作成できます。
ES2015とは?
ES2015(ES6)は、ECMAScript 6th editionの6を取ってES6と呼ばれることもあります(正式名称はES2015)。
ただし、どちらの名称でも問題はないです。エンジニアコミュニティではES6の名称の方が浸透しているらしい。
大文字と小文字を区別する
JavaScriptは大文字小文字を区別します。たとえば、次のようにnameという変数を大文字と小文字で書いた場合に、 それぞれは別々のnameとNAMEという名前の変数として認識されます。
// `name`という名前の変数を宣言
const name = "azu";
// `NAME`という名前の変数を宣言
const NAME = "azu";
また、大文字で開始しなければならない訳ではありません。あくまで別々の名前として認識されるというだけになっています。
予約語を持つ
JavaScriptには特別な意味を持つキーワードのことを予約語と言います。 このキーワードと同じ名前の変数や関数は宣言できません。 先ほどの、変数を宣言するconstも予約語のひとつです。 そのためconstという名前の変数名は宣言できません。
文はセミコロンで区切られる
JavaScriptは、文(Statement)ごとに処理していき、文はセミコロン(;)によって区切られます。 特殊なルールに基づき、セミコロンがない文も、行末に自動でセミコロンが挿入されるという仕組みも持っています。1 しかし、暗黙的なものへ頼ると意図しない挙動が発生するため、セミコロンは常に書くようにします (詳細は「文と式」の章で解説します)。
また、スペース、タブ文字などは空白文字(ホワイトスペース)と呼ばれます。 これらの空白文字を文にいくつ置いても挙動に違いはありません。たとえば、次の1足す1を行う2つの文は、+の前後の空白文字の個数に違いはありますが、動作としてはまったく同じ意味となります。
// 式や文の間にスペースがいくつあっても同じ意味となる
1 + 1;
1 + 1;
strict mode
JavaScriptにはstrict modeという実行モードが存在しています。 名前のとおり厳格な実行モードで、古く安全でない構文や機能が一部禁止されています。
"use strict"という文字列をファイルまたは関数の先頭に書くことで、そのスコープにあるコードはstrict modeで実行されます。 また、後述する"Module"の実行コンテキストでは、このstrict modeがデフォルトとなっています。
"use strict";
// このコードはstrict modeで実行される
strict modeでは、evalやwithといったレガシーな機能や構文を禁止します。 また、明らかな問題を含んだコードに対しては早期的に例外を投げることで、開発者が間違いに気づきやすくしてくれます。
たとえば、次のようなconstなどのキーワードを含まずに変数を宣言しようとした場合に、strict modeでは例外が発生します。 strict modeでない場合は、例外が発生せずにグローバル変数が作られます。
"use strict";
mistypedVariable = 42; // => ReferenceError
このように、strict modeでは開発者が安全にコードを書けるように、JavaScriptの落とし穴を一部ふさいでくれます。 そのため、常にstrict modeで実行できるコードを書くことが、より安全なコードにつながります。
本学習では、明示的に「strict modeではない」ことを宣言した場合を除き、 すべてstrict modeとして実行できるコードを扱います。
実行コンテキスト: ScriptとModule
JavaScriptの実行コンテキストとして"Script"と"Module"があります。 コードを書く場合には、この2つの実行コンテキストの違いを意識することは多くありません。
"Script"の実行コンテキストは、多くの実行環境ではデフォルトの実行コンテキストです。 "Script"の実行コンテキストでは、デフォルトはstrict modeではありません。
"Module"の実行コンテキストは、JavaScriptをモジュールとして実行するために、ECMAScript 2015で導入されたものです。 "Module"の実行コンテキストでは、デフォルトがstrict modeとなり、古く安全でない構文や機能は一部禁止されています。 また、モジュールの機能は"Module"の実行コンテキストでしか利用できません。モジュールについての詳細は「ECMAScriptモジュール」の章で解説します。
JavaScriptの仕様は毎年更新される
最後に、JavaScriptの仕様であるECMAScriptは毎年更新され、JavaScriptには新しい構文や機能が増え続けています。そのため今後もまだまだ知らなかったことが出てくるはずです。
一方で、ECMAScriptは後方互換性が慎重に考慮されているため、過去に書いたJavaScriptのコードが動かなくなる変更はほとんど入りません。 そのため、この書籍で学んだことのすべてが無駄になることはありません。
ECMAScriptの仕様がどのように策定されているかについては「ECMAScript」の章で解説します。
◆コメント
コメントはプログラムとして評価されないため、ソースコードの説明を書くために利用されています。 この書籍でも、JavaScriptのソースコードを解説するためにコメントを使っていきます。
コメントの書き方には、一行コメントと複数行コメントの2種類があります。
一行コメント
一行コメントは名前のとおり、一行ずつコメントを書く際に利用します。 // 以降から行末までがコメントとして扱われるため、プログラムとして評価されません。
// 一行コメント
// この部分はコードとして評価されない
複数行コメント
複数行コメントは名前のとおり、複数行のコメントを書く際に利用します。 一行コメントとは違い複数行をまとめて書けるので、長い説明を書く際に利用されています。
/* と */で囲まれた範囲がコメントとして扱われるため、プログラムとして評価されません。
/*
複数行コメント
囲まれている範囲がコードとして評価されない
*/
/* ネストされた /* 複数行コメント */ は書けない */
HTML-likeコメント
ES2015から後方互換性のための仕様としてHTML-likeコメントが追加されました。 このHTML-likeコメントは、ブラウザの実装に合わせた後方互換性のための仕様として定義されています。HTML-likeコメントは名前のとおり、HTMLのコメントと同じ表記です。
<!-- この行はコメントと認識される
console.log("この行はJavaScriptのコードとして実行される");
--> この行もコメントと認識される
ここでは、 がそれぞれ一行コメントとして認識されます。
JavaScriptをサポートしていないブラウザでは、タグを正しく認識できないために書かれたコードが表示されていました。 それを避けるためにの中をHTMLコメントで囲み、表示はされないが実行されるという回避策が取られていました。 今はタグをサポートしていないブラウザはないため、この回避策は不要です。
<script language="javascript">
<!--
document.bgColor = "brown";
// -->
</script>
一方、タグ内、つまりJavaScript内にHTMLコメントが書かれているサイトは残っています。 このようなサイトでもJavaScriptが動作するという、後方互換性のための仕様として追加されています。
歴史的経緯は別として、ECMAScriptではこのように後方互換性が慎重に取り扱われます。 ECMAScriptは一度入った仕様が使えなくなることはほとんどないため、基本文法で覚えたことが使えなくなることはありません。 一方で、仕様が更新されるたびに新しい機能が増えるため、それを学び続けることには変わりありません。
まとめ
// 以降から行末までが一行コメント /* と */で囲まれた範囲が複数行コメント HTML-likeコメントは後方互換性のためだけに存在する
◆変数と宣言
プログラミング言語には、文字列や数値などのデータに名前をつけて、繰り返し利用できるようにする変数という機能があります。JavaScriptには「これは変数です」という宣言をするキーワードとして、 const、let、varの3つがあります。
varはもっとも古くからある変数宣言のキーワードですが、意図しない動作を作りやすい問題が知られています。 そのためECMAScript 2015で、varの問題を改善するためにconstとletという新しいキーワードが導入されました。
この章ではconst、let、varの順に、それぞれの方法で宣言した変数の違いについて見ていきます。
[ES2015] const
constキーワードでは、再代入できない変数の宣言とその変数が参照する値(初期値)を定義できます。次のように、constキーワードに続いて変数名を書き、代入演算子(=)の右辺に変数の初期値を書いて変数を定義できます。
const 変数名 = 初期値;
次のコードではbookTitleという変数を宣言し、初期値が"JavaScript Primer"という文字列であることを定義しています。
const bookTitle = "JavaScript Primer";
const、let、varどのキーワードも共通の仕組みですが、変数同士を,(カンマ)で区切ることにより、同時に複数の変数を定義できます。
次のコードでは、bookTitleとbookCategoryという変数を順番に定義しています。
const bookTitle = "JavaScript Primer",
bookCategory = "プログラミング";
これは次のように書いた場合と同じ意味になります。
const bookTitle = "JavaScript Primer";
const bookCategory = "プログラミング";
また、constは再代入できない変数を宣言するキーワードです。 そのため、constキーワードで宣言した変数に対して、後から値を代入することはできません。
次のコードでは、constで宣言した変数bookTitleに対して値を再代入しているため、次のようなエラー(TypeError)が発生します。 エラーが発生するとそれ以降の処理は実行されなくなります。
const bookTitle = "JavaScript Primer";
bookTitle = "新しいタイトル"; // => TypeError: invalid assignment to const 'bookTitle'
一般的に変数への再代入は「変数の値は最初に定義した値と常に同じである」という参照透過性と呼ばれるルールを壊すため、バグを発生させやすい要因として知られています。そのため、変数に対して値を再代入する必要がない場合は、constキーワードで変数宣言することを推奨しています。
変数に値を再代入したいケースとして、ループなどの反復処理の途中で特定の変数が参照する値を変化させたい場合があります。 そのような場合には、変数への再代入が可能なletキーワードを利用します。
[ES2015] let
letキーワードでは、値の再代入が可能な変数を宣言できます。 letの使い方はconstとほとんど同じです。
次のコードでは、bookTitleという変数を宣言し、初期値を"JavaScript Primer"という文字列であることを定義しています。
let bookTitle = "JavaScript Primer";
letはconstとは異なり、初期値を指定しない変数も定義できます。 初期値が指定されなかった変数はデフォルト値としてundefinedという値で初期化されます(undefinedは値が未定義ということを表す値です)。
次のコードでは、bookTitleという変数を宣言しています。 このときbookTitleには初期値が指定されていないため、デフォルト値としてundefinedで初期化されます。
let bookTitle;
// `bookTitle`は自動的に`undefined`という値になる
このletで宣言されたbookTitleという変数には、代入演算子(=)を使うことで値を代入できます。 代入演算子(=)の右側には変数へ代入する値を書きますが、ここでは"JavaScript Primer"という文字列を代入しています。
let bookTitle;
bookTitle = "JavaScript Primer";
letで宣言した変数に対しては何度でも値の代入が可能です。
let count = 0;
count = 1;
count = 2;
count = 3;
var
varキーワードでは、値の再代入が可能な変数を宣言できます。 varの使い方はletとほとんど同じです。
var bookTitle = "JavaScript Primer";
varでは、letと同じように初期値がない変数を宣言でき、変数に対して値の再代入もできます。
var bookTitle;
bookTitle = "JavaScript Primer";
bookTitle = "新しいタイトル";
varの問題 varはletとよく似ていますが、varキーワードには同じ名前の変数を再定義できてしまう問題があります。
letやconstでは、同じ名前の変数を再定義しようとすると、次のような構文エラー(SyntaxError)が発生します。 そのため、間違えて変数を二重に定義してしまうというミスを防ぐことができます。
// "x"という変数名で変数を定義する
let x;
// 同じ変数名の変数"x"を定義するとSyntaxErrorとなる
let x; // => SyntaxError: redeclaration of let x
一方、varは同じ名前の変数を再定義できます。 これは意図せずに同じ変数名で定義してもエラーとならずに、値を上書きしてしまいます。
// "x"という変数を定義する
var x = 1;
// 同じ変数名の変数"x"を定義できる
var x = 2;
// 変数xは2となる
またvarには変数の巻き上げと呼ばれる意図しない挙動があり、letやconstではこの問題が解消されています。 varによる変数の巻き上げの問題については「関数とスコープ」の章で解説します。 そのため、現時点では「letはvarを改善したバージョン」ということだけ覚えておくとよいです。
このように、varにはさまざまな問題があります。 また、ほとんどすべてのケースでvarはconstかletに置き換えが可能です。 そのため、これから書くコードに対してvarを利用することは避けたほうがよいでしょう。
なぜletやconstは追加されたのか?
ES2015では、varそのものを改善するのではなく、新しくconstとletというキーワードを追加することで、varの問題を回避できるようにしました。var自体の動作を変更しなかったのは、後方互換性のためです。
なぜなら、varの挙動自体を変更してしまうと、すでにvarで書かれたコードの動作が変わってしまい、動かなくなるアプリケーションが出てくるためです。 新しくconstやletなどのキーワードをECMAScript仕様に追加しても、そのキーワードを使っているソースコードは追加時点では存在しません。1 そのため、constやletが追加されても後方互換性には影響がありません。
このように、ECMAScriptでは機能を追加する際にも後方互換性を重視しているため、var自体の挙動は変更されませんでした。
変数名に使える名前のルール
ここまででconst、let、varでの変数宣言とそれぞれの特徴について見てきました。 どのキーワードにおいても宣言できる変数に利用できる名前のルールは同じです。 また、このルールは変数の名前や関数の名前といったJavaScriptの識別子において共通するルールとなります。
変数名の名前(識別子)には、次のルールがあります。
半角のアルファベット、(アンダースコア)、$(ダラー)、数字を組み合わせた名前にする 変数名は数字から開始できない 予約語と被る名前は利用できない 変数の名前は、半角のアルファベットであるAからZ(大文字)とaからz(小文字)、(アンダースコア)、$(ダラー)、数字の0から9を組み合わせた名前にします。 JavaScriptでは、アルファベットの大文字と小文字は区別されます。
これらに加えて、ひらがなや一部の漢字なども変数名に利用できますが、全角の文字列が混在すると環境によって扱いにくいこともあるためお勧めしません。
let $; // OK: $が利用できる
let _title; // OK: _が利用できる
let jquery; // OK: 小文字のアルファベットが利用できる
let TITLE; // OK: 大文字のアルファベットが利用できる
let es2015; // OK: 数字は先頭以外なら利用できる
let 日本語の変数名; // OK: 一部の漢字や日本語も利用できる
変数名に数字を含めることはできますが、変数名を数字から開始することはできません。 これは変数名と数値が区別できなくなってしまうためです。
let 1st; // NG: 数字から始まっている
let 123; // NG: 数字のみで構成されている
また、予約語として定義されているキーワードは変数名には利用できません。 予約語とは、letのように構文として意味を持つキーワードのことです。 予約語の一覧は予約語 - JavaScript | MDNで確認できますが、基本的には構文として利用される名前が予約されています。
let let; // NG: `let`は変数宣言のために予約されているので利用できない
let if; // NG: `if`はif文のために予約されているので利用できない
constは定数ではない
constは「再代入できない変数」を定義する変数宣言であり、必ずしも定数を定義するわけではありません。 定数とは、一度定義した名前(変数名)が常に同じ値を示すものです。
JavaScriptでも、const宣言によって定数に近い変数を定義できます。 次のように、const宣言によって定義した変数を、変更できないプリミティブな値で初期化すれば、それは実質的に定数です。 プリミティブな値とは、数値や文字列などオブジェクト以外のデータです(詳細は「データ型とリテラル」の章で解説します)。
// TEN_NUMBERという変数は常に10という値を示す
const TEN_NUMBER = 10;
しかし、JavaScriptではオブジェクトなどもconst宣言できます。 次のコードのように、オブジェクトという値そのものは、初期化したあとでも変更できます。
// `const`でオブジェクトを定義している
const object = {
key: "値"
};
// オブジェクトそのものは変更できてしまう
object.key = "新しい値";
このように、constで宣言した変数が常に同じ値を示すとは限らないため、定数とは呼べません (詳細は「オブジェクト」の章で解説します)。
またconstには、変数名の命名規則はなく、代入できる値にも制限はありません。 そのため、const宣言の特性として「再代入できない変数」を定義すると理解しておくのがよいでしょう。
まとめ
constは、再代入できない変数を宣言できる letは、再代入ができる変数を宣言できる varは、再代入ができる変数を宣言できるが、いくつかの問題が知られている 変数の名前(識別子)には利用できる名前のルールがある varはほとんどすべてのケースでletやconstに置き換えが可能です。 constは再代入できない変数を定義するキーワードです。再代入を禁止することで、ミスから発生するバグを減らすことが期待できます。 このため変数を宣言する場合には、まずconstで定義できないかを検討し、できない場合はletを使うことを推奨しています。
◆データ型とリテラル
データ型
JavaScriptは動的型付け言語に分類される言語であるため、静的型付け言語のような変数の型はありません。 しかし、文字列、数値、真偽値といった値の型は存在します。 これらの値の型のことをデータ型と呼びます。
データ型を大きく分けると、プリミティブ型とオブジェクトの2つに分類されます。
プリミティブ型(基本型)は、真偽値や数値などの基本的な値の型のことです。 プリミティブ型の値は、一度作成したらその値自体を変更できないというイミュータブル(immutable)の特性を持ちます。 JavaScriptでは、文字列も一度作成したら変更できないイミュータブルの特性を持ち、プリミティブ型の一種として扱われます。
一方、プリミティブ型ではないものをオブジェクト(複合型)と呼び、 オブジェクトは複数のプリミティブ型の値またはオブジェクトからなる集合です。 オブジェクトは、一度作成した後もその値自体を変更できるためミュータブル(mutable)の特性を持ちます。 オブジェクトは、値そのものではなく値への参照を経由して操作されるため、参照型のデータとも言います。
データ型を細かく見ていくと、7つのプリミティブ型とオブジェクトからなります。
プリミティブ型(基本型) 真偽値(Boolean): trueまたはfalseのデータ型 数値(Number): 42 や 3.14159 などの数値のデータ型 巨大な整数(BigInt): ES2020から追加された9007199254740992nなどの任意精度の整数のデータ型 文字列(String): "JavaScript" などの文字列のデータ型 undefined: 値が未定義であることを意味するデータ型 null: 値が存在しないことを意味するデータ型 シンボル(Symbol): ES2015から追加された一意で不変な値のデータ型 オブジェクト(複合型) プリミティブ型以外のデータ オブジェクト、配列、関数、クラス、正規表現、Dateなど プリミティブ型でないものは、オブジェクトであると覚えていれば問題ありません。
typeof演算子を使うことで、次のようにデータ型を調べることができます。
console.log(typeof true);// => "boolean"
console.log(typeof 42); // => "number"
console.log(typeof 9007199254740992n); // => "bigint"
console.log(typeof "JavaScript"); // => "string"
console.log(typeof Symbol("シンボル"));// => "symbol"
console.log(typeof undefined); // => "undefined"
console.log(typeof null); // => "object"
console.log(typeof ["配列"]); // => "object"
console.log(typeof { "key": "value" }); // => "object"
console.log(typeof function() {}); // => "function"
実行後
boolean
number
bigint
string
symbol
undefined
object
object
object
function
プリミティブ型の値は、それぞれtypeof演算子の評価結果として、その値のデータ型を返します。 一方で、オブジェクトに分類される値は"object"となります。
配列([])とオブジェクト({})は、どちらも"object"という判定結果になります。 そのため、typeof演算子ではオブジェクトの詳細な種類を正しく判定することはできません。 ただし、関数はオブジェクトの中でも特別扱いされているため、typeof演算子の評価結果は"function"となります。 また、typeof nullが"object"となるのは、歴史的経緯のある仕様のバグ1です。
このことからもわかるようにtypeof演算子は、プリミティブ型またはオブジェクトかを判別するものです。 typeof演算子では、オブジェクトの詳細な種類を判定できないことは、覚えておくとよいでしょう。 各オブジェクトの判定方法については、それぞれのオブジェクトの章で見ていきます。
リテラル
プリミティブ型の値や一部のオブジェクトは、リテラルを使うことで簡単に定義できるようになっています。
リテラルとはプログラム上で数値や文字列など、データ型の値を直接記述できるように構文として定義されたものです。 たとえば、"と"で囲んだ範囲が文字列リテラルで、これは文字列型のデータを表現しています。
次のコードでは、"こんにちは"という文字列型のデータを初期値に持つ変数strを定義しています。
// "と"で囲んだ範囲が文字列リテラル
const str = "こんにちは";
リテラル表現がない場合は、その値を作る関数に引数を渡して作成する形になります。 そのような冗長な表現を避ける方法として、よく利用される主要なデータ型にはリテラルが用意されています。
次の4つのプリミティブ型は、それぞれリテラル表現を持っています。
真偽値 数値 文字列 null また、オブジェクトの中でもよく利用されるものに関してはリテラル表現が用意されています。
オブジェクト 配列 正規表現 これらのリテラルについて、まずはプリミティブ型から順番に見ていきます。
真偽値(Boolean)
真偽値にはtrueとfalseのリテラルがあります。 それぞれはtrueとfalseの値を返すリテラルで、見た目どおりの意味となります。
true; // => true
false; // => false
実行後
false
数値(Number)
数値には42のような整数リテラルと3.14159のような浮動小数点数リテラルがあります。
これらのリテラルで表現できる数値はIEEE 754の倍精度浮動小数として扱われます。 倍精度浮動小数では64ビットで数値を表現します。 64ビットのうち52ビットを数字の格納のために使い、11ビットを小数点の位置に使い、残りの1ビットはプラスとマイナスの符号です。 そのため、正確に扱える数値の最大値は2^53-1(2の53乗から1引いた値)となります。
整数リテラル
整数リテラルには次の4種類があります。
10進数: 数字の組み合わせ ただし、複数の数字を組み合わせた際に、先頭を0から開始すると8進数として扱われる場合があります 例)0、2、10 2進数: 0b(または0B)の後ろに、0または1の数字の組み合わせ 例)0b0、0b10、0b1010 8進数: 0o(または0O)の後ろに、0から7までの数字の組み合わせ 0o は数字のゼロと小文字アルファベットのo 例)0o644、0o777 16進数: 0x(または0X)の後ろに、0から9までの数字とaからfまたはAからFのアルファベットの組み合わせ アルファベットの大文字・小文字の違いは値には影響しません 例)0x30A2、0xEEFF 0から9の数字のみで書かれた数値は、10進数として扱われます。
console.log(1); // => 1
console.log(10); // => 10
console.log(255); // => 255
実行後
1
10
255
0bからはじまる2進数リテラルは、ビットを表現するのによく利用されています。 bは2進数を表すbinaryを意味しています。
console.log(0b1111); // => 15
console.log(0b10000000000); // => 1024
実行後
15
1024
0oからはじまる8進数リテラルは、ファイルのパーミッションを表現するのによく利用されています。 oは8進数を表すoctalを意味しています。
console.log(0o644); // => 420
console.log(0o777); // => 511
実行後
420
511
次のように、0からはじまり、0から7の数字を組み合わせた場合も8進数として扱われます。 しかし、この表記は10進数と紛らわしいものであったため、ES2015で0oの8進数リテラルが新たに導入されました。 また、strict modeではこの書き方は例外が発生するため、次のような8進数の書き方は避けるべきです(詳細は「JavaScriptとは」のstrict modeを参照)。
// 非推奨な8進数の書き方
// strict modeは例外が発生
console.log(0644); // => 420
console.log(0777); // => 511
実行後
420
511
0xからはじまる16進数リテラルは、文字のコードポイントやRGB値の表現などに利用されています。 xは16進数を表すhexを意味しています。
console.log(0xFF); // => 255
// 小文字で書いても意味は同じ
console.log(0xff); // => 255
console.log(0x30A2); // => 12450
255
255
12450
浮動小数点数リテラル
浮動小数点数をリテラルとして書く場合には、次の2種類の表記が利用できます。
3.14159 のような .(ドット)を含んだ数値 2e8 のような e または E を含んだ数値 0からはじまる浮動小数点数は、0を省略して書くことができます。
.123; // => 0.123
実行後
0.123
しかし、JavaScriptでは.をオブジェクトにおいて利用する機会が多いため、 0からはじまる場合でも省略せずに書いたほうが意図しない挙動を減らせるでしょう。
Note 変数名を数字からはじめることができないのは、数値リテラルと衝突してしまうからです。
eは指数(exponent)を意味する記号で、eのあとには指数部の値を書きます。 たとえば、2e8は2×10の8乗となるので、10進数で表すと200000000となります。
2e8; // => 200000000
実行後
200000000
[ES2020] BigInt
JavaScriptでは、1や3.14159などの数値リテラルはIEEE 754で定義された倍精度浮動小数となります。 倍精度浮動小数で正確に扱える数値の最大値は2^53-1(2の53乗から1引いた値である9007199254740991)です。 この数値リテラルで安全に表せる最大の数値はNumber.MAX_SAFE_INTEGERとして定義されています。
console.log(Number.MAX_SAFE_INTEGER); // => 9007199254740991
数値リテラルで2^53-1(9007199254740991)よりも大きな値を表現したり計算すると間違った結果となる場合があります。
この問題を解決するために、ES2020ではBigIntという新しい整数型のデータ型とリテラルが追加されました。 数値リテラルは倍精度浮動小数(64ビット)で数値を扱うのに対して、BigIntでは任意の精度の整数を扱えます。 そのため、BigIntでは2^53-1(9007199254740991)よりも大きな整数を正しく表現できます。
BigIntリテラルは、数値の後ろにnをつけます。
console.log(1n); // => 1n
// 2^53-1より大きな値も扱える
console.log(9007199254740992n); // => 9007199254740992n
実行後
1
9007199254740992
BigIntは整数を扱うデータ型であるため、次のように小数点を含めた場合は構文エラーとなります。
1.2n; // => SyntaxError
[ES2021] Numeric Separators
数値が大きくなるほど、桁数の見間違いなどが発生しやすくなります。 次のコードは、1兆を数値リテラルで書いていますが、桁数を読み取りにくいです。
1000000000000;
ES2021から、数値リテラル内の区切り文字として_を追加できるNumeric Separatorsがサポートされています。 Numeric Separatorsは、数値リテラル内では区切り文字として_が追加できます。 次のコードも、1兆を数値リテラルで書いています。数値リテラルを評価する際に_は単純に無視されるため同じ意味となります。
1_000_000_000_000;
実行後
1000000000000
Numeric Separatorsは数値リテラルである整数、浮動小数点、BigIntのリテラル内でのみ利用できます。 また、_はリテラルの先頭や数値の最後に追加することはできません。
_123; // 変数として評価される
3._14; // => SyntaxError
0x52_; // => SyntaxError
1234n_; // => SyntaxError
文字列(String)
文字列リテラル共通のルールとして、同じ記号で囲んだ内容を文字列として扱います。 文字列リテラルとして次の3種類のリテラルがありますが、その評価結果はすべて同じ"文字列"になります。
console.log("文字列"); // => "文字列"
console.log('文字列'); // => "文字列"
console.log(`文字列`); // => "文字列"
実行後
文字列
文字列
文字列