ECMAScript 2015、通称ES6、ではJavaScriptのクラスが導入されました。

JavaScriptのクラスはJavaScriptオブジェクトのテンプレートです。

JavaScriptクラスの構文

クラスを作成するには、キーワードclassを使用します。

必ずconstructor()という名前のメソッドを追加してください:


class ClassName {
  constructor() { ... }
}


class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
}

上記の例は”Car”という名前のクラスを作成します。

このクラスには2つの初期プロパティ、”name”と”year”があります。

JavaScriptのクラスはオブジェクトではありません。

それはJavaScriptオブジェクトのテンプレートです。

クラスの使用

クラスがあれば、そのクラスを使用してオブジェクトを作成できます:


const myCar1 = new Car("Ford", 2014);
const myCar2 = new Car("Audi", 2019);

上記の例ではCarクラスを使用して2つのCarオブジェクトを作成します。

新しいオブジェクトが作成されるときに、constructorメソッドが自動的に呼び出されます。

constructorメソッド

constructorメソッドは特別なメソッドです:

constructorメソッドを定義しない場合、JavaScriptは空のconstructorメソッドを追加します。

クラスメソッド

クラスメソッドはオブジェクトメソッドと同じ構文で作成されます。

クラスを作成するにはキーワードclassを使用します。

必ずconstructor()メソッドを追加します。

その後、任意の数のメソッドを追加します。


class ClassName {
  constructor() { ... }
  method_1() { ... }
  method_2() { ... }
  method_3() { ... }
}

「age」という名前のクラスメソッドを作成し、Carの年齢を返すようにします:


class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
  age() {
    const date = new Date();
    return date.getFullYear() - this.year;
  }
}

const myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML =
"My car is " + myCar.age() + " years old.";

クラスメソッドにパラメータを渡すこともできます:


class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
  age(x) {
    return x - this.year;
  }
}

const date = new Date();
let year = date.getFullYear();

const myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML =
"My car is " + myCar.age(year) + " years old.";

Arrow functionsはES6で導入されました。

Arrow functionsを使うと、より短い関数構文を記述できます:


let myFunction = (a, b) => a * b;

Arrow Functionの導入前:


hello = function() {
  return "Hello World!";
}

Arrow Functionを使った場合:


hello = () => {
  return "Hello World!";
}

もっと短くなりました!関数が単一のステートメントで、そのステートメントが値を返す場合、中括弧とreturnキーワードを省略できます:

Arrow Functionはデフォルトで値を返します:


hello = () => "Hello World!";

Note: この省略形は、関数が単一のステートメントの場合にのみ有効です。

パラメータがある場合は、それらを括弧内に渡します:

パラメータを持つArrow Function:


hello = (val) => "Hello " + val;

実際、パラメータが1つしかない場合は括弧を省略することもできます:

括弧なしのArrow Function:


hello = val => "Hello " + val;

thisはどうなる?

Arrow Functionでは、通常の関数と比較してthisの扱いが異なります。

簡単に言うと、Arrow Functionではthisのバインディングがありません。

通常の関数では、thisキーワードは関数を呼び出したオブジェクトを表しました。それはウィンドウ、ドキュメント、ボタンなどでした。

しかしArrow Functionでは、thisキーワードは常にArrow Functionを定義したオブジェクトを指します。

この違いを理解するために、2つの例を見てみましょう。

両方の例では、ページの読み込み時に1回、ボタンのクリック時にもう1回メソッドを呼び出します。

最初の例では通常の関数を使用し、2番目の例ではArrow Functionを使用します。

結果は、最初の例が異なる2つのオブジェクト(ウィンドウとボタン)を返し、2番目の例が2回ともウィンドウオブジェクトを返すことを示しています。これは、ウィンドウオブジェクトが関数の「所有者」であるためです。

通常の関数を使った場合、thisは関数を呼び出したオブジェクトを表します:


// 通常の関数:
hello = function() {
  document.getElementById("demo").innerHTML += this;
}

// ウィンドウオブジェクトが関数を呼び出します:
window.addEventListener("load", hello);

// ボタンオブジェクトが関数を呼び出します:
document.getElementById("btn").addEventListener("click", hello);

Arrow Functionを使った場合、thisは関数を定義したオブジェクトを表します:


// Arrow Function:
hello = () => {
  document.getElementById("demo").innerHTML += this;
}

// ウィンドウオブジェクトが関数を呼び出します:
window.addEventListener("load", hello);

// ボタンオブジェクトが関数を呼び出します:
document.getElementById("btn").addEventListener("click", hello);

関数を扱う際にはこれらの違いを覚えておいてください。通常の関数の挙動が必要な場合もありますが、そうでない場合はArrow Functionを使用してください。

例:


const person = {
  firstName: "John",
  lastName : "Doe",
  id       : 5566,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

thisとは何ですか?

JavaScriptでは、thisキーワードはオブジェクトを参照します。

thisキーワードの参照先は、使用方法によって異なります:

Note: thisは変数ではなくキーワードです。thisの値を変更することはできません。

thisを使ったメソッド内での使用例

オブジェクトのメソッド内で使用する場合、thisはそのオブジェクトを指します。

前述の例では、fullNameメソッドはpersonオブジェクトのメソッドであるため、thisはpersonオブジェクトを指します。


fullName : function() {
  return this.firstName + " " + this.lastName;
}

this単体での使用

単体で使用すると、thisはグローバルオブジェクトを指します。

これはグローバルスコープで実行されるためです。

ブラウザのウィンドウでは、グローバルオブジェクトは[object Window]です:


let x = this;

厳密モードでは、単体で使用する場合もthisはグローバルオブジェクトを指します:


"use strict";
let x = this;

関数内でのthis(デフォルト)

関数内では、デフォルトでthisはグローバルオブジェクトにバインドされます。

ブラウザのウィンドウでは、グローバルオブジェクトは[object Window]です:


function myFunction() {
  return this;
}

関数内でのthis(厳密モード)

JavaScriptの厳密モードでは、デフォルトのバインディングが許可されません。

そのため、関数内で厳密モードを使用すると、thisは未定義になります。


"use strict";
function myFunction() {
  return this;
}

イベントハンドラ内でのthis

HTMLのイベントハンドラ内では、thisはイベントを受け取ったHTML要素を指します:



オブジェクトメソッドのバインディング

以下の例では、thisはpersonオブジェクトです:


const person = {
  firstName  : "John",
  lastName   : "Doe",
  id         : 5566,
  myFunction : function() {
    return this;
  }
};

また、次のようにも使用されます:


const person = {
  firstName: "John",
  lastName : "Doe",
  id       : 5566,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

つまり、this.firstNameはthis(personオブジェクト)のfirstNameプロパティです。

明示的な関数のバインディング

call()メソッドとapply()メソッドは、事前定義されたJavaScriptのメソッドです。

これらはどちらも別のオブジェクトを引数としてオブジェクトのメソッドを呼び出すために使用されます。

以下の例では、person1.fullNameをperson2を引数にして呼び出し、thisをperson2に指定しています。fullNameはperson1のメソッドですが、thisはperson2を指します:


const person1 = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

const person2 = {
  firstName:"John",
  lastName: "Doe",
}

// "John Doe"を返します:
person1.fullName.call(person2);

関数の借用

bind()メソッドを使用すると、オブジェクトは別のオブジェクトからメソッドを借りることができます。

次の例では、2つのオブジェクト(personとmember)を作成します。

memberオブジェクトはpersonオブジェクトからfullNameメソッドを借ります:


const person = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this.firstName + " " + this.lastName;
  }
}

const member = {
  firstName:"Hege",
  lastName: "Nilsen",
}

let fullName = person.fullName.bind(member);

優先順位

thisがどのオブジェクトを指すかを決定するために、以下の優先順位を使用します。

優先順位 オブジェクト
1 bind()
2 apply()とcall()
3 オブジェクトのメソッド
4 グローバルスコープ

スコープは変数のアクセス可能性(可視性)を決定します。

JavaScriptの変数には3つのスコープがあります:

ブロックスコープ

ES6(2015年)以前は、JavaScriptの変数はグローバルスコープと関数スコープのみでした。

ES6では、letとconstという2つの重要な新しいJavaScriptのキーワードが導入され、ブロックスコープを提供します。

{ }ブロック内で宣言された変数は、外部からアクセスできません:


{
  let x = 2;
}
// ここではxは使用できません

varキーワードで宣言された変数にはブロックスコープがありません。

{ }ブロック内で宣言された変数は、外部からアクセスできます。


{
  var x = 2;
}
// ここではxを使用できます

ローカルスコープ

JavaScript関数内で宣言された変数は、その関数にローカル(局所)です:


// ここでcarNameは使用できません

function myFunction() {
  let carName = "Volvo";
  // ここではcarNameを使用できます
}

// ここでcarNameは使用できません

ローカル変数は関数内部からのみアクセス可能です:

ローカル変数は、関数が開始されると作成され、関数が完了すると削除されます。

関数スコープ

JavaScriptには関数スコープがあります。各関数は新しいスコープを作成します。

関数内で定義された変数は、その関数の外部からアクセスできません。

関数内でvar、let、constで宣言された変数は、関数スコープを持ちます。


function myFunction() {
  var carName = "Volvo";   // 関数スコープ
}
function myFunction() {
  let carName = "Volvo";   // 関数スコープ
}
function myFunction() {
  const carName = "Volvo";   // 関数スコープ
}

グローバルJavaScript変数

関数外で宣言された変数は、グローバル変数になります。


let carName = "Volvo";
// ここでcarNameを使用できます

function myFunction() {
  // ここでもcarNameを使用できます
}

グローバル変数は、グローバルスコープを持ちます:

Webページ上のすべてのスクリプトと関数からアクセスできます。

var、let、constで宣言された変数は、ブロックの外で宣言された場合、すべてグローバルスコープを持ちます。


var x = 2;       // グローバルスコープ
let x = 2;       // グローバルスコープ
const x = 2;       // グローバルスコープ

JavaScript変数

JavaScriptでは、オブジェクトや関数も変数です。

スコープは、コードの異なる部分から変数、オブジェクト、および関数にアクセスする可否を決定します。

自動的にグローバル

宣言されていない変数に値を割り当てると、その変数は自動的にグローバル変数になります。

このコード例では、関数内で値を割り当てても、carNameはグローバル変数として宣言されます。


myFunction();

// ここでcarNameを使用できます

function myFunction() {
  carName = "Volvo";
}

厳密モード

すべてのモダンブラウザはJavaScriptを「厳密モード」で実行することをサポートしています。

厳密モードの使用方法については、このチュートリアルの後の章で詳しく学びます。

「厳密モード」では、宣言されていない変数は自動的にグローバルになりません。

HTMLにおけるグローバル変数

JavaScriptでは、グローバルスコープはJavaScriptの環境です。

HTMLでは、グローバルスコープはwindowオブジェクトです。

varキーワードで定義されたグローバル変数は、windowオブジェクトに属します:


var carName = "Volvo";
// ここでcarNameを使用できます window.carName

letキーワードで定義されたグローバル変数は、windowオブジェクトに属しません:


let carName = "Volvo";
// ここではcarNameを使用できません window.carName

警告

意図しない場合はグローバル変数を作成しないでください。

グローバル変数(または関数)は、windowの変数(または関数)を上書きする可能性があります。

任意の関数、windowオブジェクトを含めて、グローバル変数と関数を上書きすることができます。

JavaScript変数のライフタイム

JavaScript変数のライフタイムは、宣言された時から始まります。

関数(ローカル)変数は、関数が完了すると削除されます。

Webブラウザでは、グローバル変数はブラウザウィンドウ(またはタブ)を閉じると削除されます。

関数の引数

関数の引数(パラメータ)は、関数内でローカル変数として機能します。

Throw, and Try…Catch…Finally

try文は、実行するコードブロック(試す)を定義します。

catch文は、任意のエラーを処理するコードブロックを定義します。

finally文は、結果に関係なく実行するコードブロックを定義します。

throw文は、カスタムエラーを定義します。

エラーは起こるものとして受け入れる

JavaScriptコードを実行する際、さまざまなエラーが発生する可能性があります。

エラーは、プログラマーが作成したコーディングエラー、誤った入力によるエラー、その他予測不可能な要因によるものがあります。

Example

この例では、意図的にエラーを発生させるために「alert」を「adddlert」と誤って綴りました:


<p id="demo"></p>

<script>
try {
  adddlert("Welcome guest!");
}
catch(err) {
  document.getElementById("demo").innerHTML = err.message;
}
</script>

JavaScriptはadddlertをエラーとしてキャッチし、catchブロックでそのエラーを処理します。

JavaScriptのtryとcatch

try文は、実行中にエラーが発生するかどうかをテストするためのコードブロックを定義します。

catch文は、tryブロックでエラーが発生した場合に実行するコードブロックを定義します。

JavaScriptのtryとcatchは以下のようにペアで使用されます:


try {
  // 試すコードブロック
}
catch(err) {
  // エラーを処理するコードブロック
}

JavaScriptでのエラーのスロー

エラーが発生すると、JavaScriptは通常、エラーメッセージを生成して停止します。

これを技術的には「例外をスローする」と言います。

JavaScriptは実際に2つのプロパティ(nameとmessage)を持つErrorオブジェクトを作成します。

throw文

throw文を使用すると、カスタムエラーを作成できます。

技術的には、例外(エラー)をスローすることができます。


throw "Too big";    // throw a text
throw 500;          // throw a number

tryとcatchと一緒にthrowを使用すると、プログラムのフローを制御し、カスタムエラーメッセージを生成できます。

入力検証の例

この例では入力を検証します。値が間違っている場合、例外(err)がスローされます。

catch文で例外(err)をキャッチし、カスタムエラーメッセージを表示します:


<!DOCTYPE html>
<html>
<body>

<p>5から10の間の数字を入力してください:</p>

<input id="demo" type="text">
<button type="button" onclick="myFunction()">入力をテスト</button>
<p id="p01"></p>

<script>
function myFunction() {
  const message = document.getElementById("p01");
  message.innerHTML = "";
  let x = document.getElementById("demo").value;
  try {
    if(x.trim() == "") throw "empty";
    if(isNaN(x)) throw "not a number";
    x = Number(x);
    if(x < 5) throw "too low";
    if(x > 10) throw "too high";
  }
  catch(err) {
    message.innerHTML = "入力は " + err + " です";
  }
}
</script>

</body>
</html>

HTMLの検証

上記のコードは単なる例です。

現代のブラウザは、しばしばJavaScriptと組み込みのHTML検証を組み合わせて使用し、HTML属性で定義された事前定義の検証ルールを使用します:


<input id="demo" type="number" min="5" max="10" step="1">

フォームの検証については、このチュートリアルの後の章で詳しく説明します。

finally文

finally文は、tryとcatchの結果にかかわらず、最終的に実行したいコードを定義します:


try {
  // 試すコードブロック
}
catch(err) {
  // エラーを処理するコードブロック
}
finally {
  // try / catchの結果に関わらず実行するコードブロック
}

エラーオブジェクト

JavaScriptには組み込みのエラーオブジェクトがあり、エラー発生時にエラー情報を提供します。

エラーオブジェクトには、nameとmessageという2つの有用なプロパティがあります。

エラーオブジェクトのプロパティ

プロパティ 説明
name エラーの名前を設定または返します
message エラーメッセージを設定または返します(文字列)

Error Nameの値

Error Name 説明
EvalError eval()関数でエラーが発生しました
RangeError 範囲外の数値が使用されました
ReferenceError 未宣言の変数が使用されました
SyntaxError 構文エラーが発生しました
TypeError 不適切な型のオペランドまたは引数が使用されました
URIError encodeURI()でエラーが発生しました

これら6つの異なる値については以下で説明します。

非標準のエラーオブジェクトプロパティ

MozillaとMicrosoftは、いくつかの非標準のエラーオブジェクトプロパティを定義しています:

これらのプロパティはすべてのブラウザで動作しない可能性があるため、公開ウェブサイトでの使用は避けてください。

正規表現(Regular Expression)は、検索パターンを形成する文字のシーケンスです。

この検索パターンは、テキスト検索やテキスト置換操作に使用することができます。

正規表現とは?

正規表現は、検索パターンを形成する文字のシーケンスです。

テキスト内のデータを検索する際に、この検索パターンを使用して検索対象を記述することができます。

正規表現は、単一の文字からより複雑なパターンまで様々な形式で記述できます。

正規表現は、あらゆる種類のテキスト検索やテキスト置換操作に使用することができます。

構文


/pattern/modifiers;


/codelabs-jp/i;

例の説明:


/codelabs-jp/i は正規表現です。

codelabs-jp は検索に使用するパターンです。

i は修飾子で、大文字と小文字を区別しない検索を行うように修飾します。

文字列メソッドの使用

JavaScriptでは、正規表現はしばしば、search() および replace() という2つの文字列メソッドと共に使用されます。

search() メソッドは、式を使用して一致を検索し、その一致の位置を返します。

replace() メソッドは、パターンが置換された変更された文字列を返します。

文字列 search() メソッドの使用

search() メソッドは、指定された値を検索し、その一致の位置を返します:


let text = "Visit codelabs-jp!";
let n = text.search("codelabs-jp");

n の結果は:


6

正規表現を使用した文字列 search() メソッドの使用

正規表現を使用して、大文字と小文字を区別しない検索で “codelabs-jp” を検索します:


let text = "Visit codelabs-jp";
let n = text.search(/codelabs-jp/i);

n の結果は:


6

文字列 replace() メソッドの使用

replace() メソッドは、文字列内の指定された値を別の値で置換します:


let text = "Visit Microsoft!";
let result = text.replace("Microsoft", "codelabs-jp");

正規表現を使用した文字列 replace() メソッドの使用

大文字と小文字を区別しない正規表現を使用して、”Microsoft” を “codelabs-jp” に置換します:


let text = "Visit Microsoft!";
let result = text.replace(/microsoft/i, "codelabs-jp");

res の結果は:


Visit codelabs-jp!

気づきましたか?

上記のメソッドで、文字列の代わりに正規表現の引数を使用することができます。

正規表現を使用することで、検索がより強力になります(例えば、大文字と小文字を区別しない検索など)。

正規表現修飾子

修飾子を使用すると、大文字と小文字を区別しない、より広範な検索が可能になります:

修飾子 説明
i 大文字と小文字を区別しないマッチングを実行します
g 全ての一致を見つけます(グローバルマッチ)
m 複数行マッチングを実行します
d 開始と終了のマッチングを実行します(ES2022で新規追加)

正規表現パターン

角括弧を使用して文字の範囲を見つけることができます:

説明
[abc] 角括弧内の文字のいずれかを見つけます
[0-9] 角括弧内の数字のいずれかを見つけます
(x|y) | で区切られた代替のいずれかを見つけます

メタ文字は特別な意味を持つ文字です:

メタ文字 説明
\d 数字を見つけます
\s 空白文字を見つけます
\b \bWORD のように単語の先頭、または WORD\b のように単語の末尾で一致を見つけます
\uxxxx 16進数の xxxx で指定された Unicode 文字を見つけます

量指定子は数量を定義します:

量指定子 説明
n+ 少なくとも1回の出現を持つ任意の文字列に一致します
n* 0回以上の出現を持つ任意の文字列に一致します
n? 0回または1回の出現を持つ任意の文字列に一致します

RegExp オブジェクトの使用

JavaScriptでは、RegExp オブジェクトは事前に定義されたプロパティとメソッドを持つ正規表現オブジェクトです。

test() の使用

test() メソッドは RegExp 式のメソッドです。

これはパターンを検索し、その結果に応じて true または false を返します。

次の例は、文字列内で文字 “e” を検索します:


const pattern = /e/;
pattern.test("The best things in life are free!");

上記のコードの出力は、文字列内に “e” が含まれているため、true になります。

パターンを最初に変数に入れる必要はありません。上記の2行は次のように1行で短縮することができます:


/e/.test("The best things in life are free!");

exec() の使用

exec() メソッドは RegExp 式のメソッドです。

これは指定されたパターンを検索し、見つかったテキストをオブジェクトとして返します。

もし一致するものが見つからない場合は、空の(null)オブジェクトを返します。

次の例は、文字列内で文字 “e” を検索します:


/e/.exec("The best things in life are free!");

注意点

JavaScriptでは、文字列引数の代わりに正規表現引数を使用することができます。

正規表現を使用することで、検索がより強力になります(例えば、大文字と小文字を区別しない検索など)。

JavaScript 正規表現変換テーブル

このテーブルは、さまざまな JavaScript の値を数値、文字列、ブール値に変換した結果を示しています:

元の値 数値に変換された値 文字列に変換された値 ブール値に変換された値
false 0 “false” false
true 1 “true” true
0 0 “0” false
1 1 “1” true
“0” 0 “0” true
“000” 0 “000” true
“1” 1 “1” true
NaN NaN “NaN” false
Infinity Infinity “Infinity” true
-Infinity -Infinity “-Infinity” true
“” 0 “” false
“20” 20 “20” true
“twenty” NaN “twenty” true
[] 0 “” true
[20] 20 “20” true
[10,20] NaN “10,20” true
[“twenty”] NaN “twenty” true
[“ten”,”twenty”] NaN “ten,twenty” true
function(){} NaN “function(){}” true
{ } NaN “[object Object]” true
null 0 “null” false
undefined NaN “undefined” false

文字列から数値への変換

グローバルメソッドNumber()は、変数(または値)を数値に変換します。


Number("3.14")
Number(Math.PI)
Number(" ")
Number("")

これらは変換されますが:


Number("99 88")
Number("John")

メソッド

Number Methods章では、文字列を数値に変換するための他のメソッドも紹介されています:

メソッド 説明
Number() 引数を数値に変換して返す
parseFloat() 文字列を解析して浮動小数点数を返す
parseInt() 文字列を解析して整数を返す

単項+演算子

単項+演算子は変数を数値に変換するために使用できます。


let y = "5";      // yは文字列
let x = + y;      // xは数値

変数を変換できない場合、値はNaN(数値でないことを表す特別な値)になります:


let y = "John";   // yは文字列
let x = + y;      // xは数値(NaN)

数値から文字列への変換

グローバルメソッドString()は、数値を文字列に変換します。

リテラル、変数、または式で使用できます。


String(x)         // 数値変数xを文字列に変換
String(123)       // 数値リテラル123を文字列に変換
String(100 + 23)  // 式からの数値を文字列に変換

NumberメソッドのtoString()も同様のことができます。


x.toString()
(123).toString()
(100 + 23).toString()

メソッド

Number Methods章では、数値を文字列に変換するための他のメソッドも紹介されています:

メソッド 説明
toExponential() 数値を指数表記で文字列に変換して返す
toFixed() 数値を指定した小数点以下の桁数で文字列に変換して返す
toPrecision() 数値を指定した長さで文字列に変換して返す

日付から数値への変換

グローバルメソッドNumber()は、日付を数値に変換するために使用できます。


let d = new Date();
Number(d)          // 数値に変換して返す

日付メソッドgetTime()も同様のことができます。


let d = new Date();
d.getTime()        // 数値に変換して返す

日付から文字列への変換

グローバルメソッドString()は、日付を文字列に変換します。


String(Date())  // 文字列に変換して返す

DateメソッドのtoString()も同様のことができます。


Date().toString()  // 文字列に変換して返す

メソッド

Date Methods章では、日付を文字列に変換するための他のメソッドも紹介されています:

メソッド 説明
getDate() 日付を1から31の数値で取得する
getDay() 曜日を0から6の数値で取得する
getFullYear() 年を4桁で取得する
getHours() 時を0から23の数値で取得する
getMilliseconds() ミリ秒を0から999の数値で取得する
getMinutes() 分を0から59の数値で取得する
getMonth() 月を0から11の数値で取得する
getSeconds() 秒を0から59の数値で取得する
getTime() 1970年1月1日午前0時からのミリ秒数を取得する

ブーリアンから数値への変換

グローバルメソッドNumber()はブーリアンも数値に変換することができます。


Number(false)     // 0を返す
Number(true)      // 1を返す

ブーリアンから文字列への変換

グローバルメソッドString()はブーリアンを文字列に変換します。


String(false)      // "false"を返す
String(true)       // "true"を返す

BooleanメソッドのtoString()も同様のことができます。


false.toString()   // "false"を返す
true.toString()    // "true"を返す

自動型変換

JavaScriptが「間違った」データ型で操作しようとすると、値を「正しい」タイプに変換しようとします。

結果は常に予想どおりではありません:


5 + null    // 5を返す、nullが0に変換されるため
"5" + null  // "5null"を返す、nullが文字列"null"に変換されるため
"5" + 2     // "52"を返す、2が文字列"2"に変換されるため
"5" - 2     // 3を返す、"5"が数値5に変換されるため
"5" * "2"   // 10を返す、"5"と"2"が数値5と2に変換されるため

自動文字列変換

JavaScriptはオブジェクトまたは変数を「出力」しようとすると、自動的に変数のtoString()関数を呼び出します。


document.getElementById("demo").innerHTML = myVar;

// if myVar = {name:"Fjohn"}  // toStringは"[object Object]"に変換されます
// if myVar = [1,2,3,4]       // toStringは"1,2,3,4"に変換されます
// if myVar = new Date()      // toStringは"Fri Jul 18 2014 09:08:55 GMT+0200"に変換されます

数値とブーリアンも変換されますが、これはあまり目立たないです:


// if myVar = 123             // toStringは"123"に変換されます
// if myVar = true            // toStringは"true"に変換されます
// if myVar = false           // toStringは"false"に変換されます

JavaScript型変換表

この表は、さまざまなJavaScriptの値を数値、文字列、ブーリアンに変換した結果を示しています:

元の値 数値に変換 文字列に変換 ブーリアンに変換
false 0 “false” false
true 1 “true” true
0 0 “0” false
1 1 “1” true
“0” 0 “0” true
“000” 0 “000” true
“1” 1 “1” true
NaN NaN “NaN” false
Infinity Infinity “Infinity” true
-Infinity -Infinity “-Infinity” true
“” 0 “” false
“20” 20 “20” true
“twenty” NaN “twenty” true
[] 0 “” true
[20] 20 “20” true
[10,20] NaN “10,20” true
[“twenty”] NaN “twenty” true
[“ten”,”twenty”] NaN “ten,twenty” true
function(){} NaN “function(){}” true
{} NaN “[object Object]” true
null 0 “null” false
undefined NaN “undefined” false

typeof演算子

typeof演算子は、JavaScript変数のデータ型を返します。

プリミティブデータ型

JavaScriptでは、プリミティブ値はプロパティやメソッドを持たない単一の値です。

JavaScriptには7つのプリミティブデータ型があります:

typeof演算子は、変数または式の型を返します。


typeof "John"         // stringを返す
typeof ("John"+"Doe") // stringを返す
typeof 3.14           // numberを返す
typeof 33             // numberを返す
typeof (33 + 66)      // numberを返す
typeof true           // booleanを返す
typeof false          // booleanを返す
typeof 1234n          // bigintを返す
typeof Symbol()       // symbolを返す
typeof x              // undefinedを返す
typeof null           // objectを返す

Note:

JavaScriptでは、nullはプリミティブ値ですが、typeof演算子は”object”を返します。

これはJavaScriptの歴史的な理由による既知のバグです。

複合データ型

複合データ型は、複数の値と/または異なるデータ型を一緒に保存できます。

JavaScriptには1つの複合データ型があります:

配列、関数、セット、マップなど、すべての他の複合型は単なる異なるタイプのオブジェクトです。

typeof演算子は次の2つのタイプのみを返します:


typeof {name:'John'}   // objectを返す
typeof [1,2,3,4]       // objectを返す
typeof new Map()       // objectを返す
typeof new Set()       // objectを返す
typeof function (){}   // functionを返す

Note:

typeof演算子は、すべてのタイプのオブジェクト(オブジェクト、配列、セット、マップ)に対してobjectを返します。

JavaScriptのオブジェクトが配列か日付かをtypeofで判断することはできません。

配列の認識方法

変数が配列かどうかを知るにはどうすればよいですか?

ECMAScript 5(2009)では、これに対する新しい方法が定義されました:Array.isArray():


// 配列を作成する
const fruits = ["apples", "bananas", "oranges"];
Array.isArray(fruits);

instanceof演算子

instanceof演算子は、オブジェクトが指定されたオブジェクト型のインスタンスである場合にtrueを返します:


// 日付を作成する
const time = new Date();

(time instanceof Date);
// 配列を作成する
const fruits = ["apples", "bananas", "oranges"];

(fruits instanceof Array);
// マップを作成する
const fruits = new Map([
  ["apples", 500],
  ["bananas", 300],
  ["oranges", 200]
]);

(fruits instanceof Map);
// セットを作成する
const fruits = new Set(["apples", "bananas", "oranges"]);

(fruits instanceof Set);

未定義の変数

未定義の変数のtypeofはundefinedです。


typeof car;

値がない変数のtypeofもundefinedです。値もundefinedです。


let car;
typeof car;

どんな変数でも、値をundefinedに設定することで空にすることができます。

型もundefinedになります。


let car = "Volvo";
car = undefined;

空の値

空の値はundefinedとは異なります。

空の文字列には有効な値と型があります。


let car = "";
typeof car;

null

JavaScriptではnullは「何もない」ことを意味します。存在しないものです。

残念ながらJavaScriptでは、nullのデータ型はobjectです。

nullを設定することでオブジェクトを空にすることができます:


// オブジェクトを作成する
let person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

person = null;
// これで値はnullになりますが、型はまだobjectです

また、undefinedに設定することでオブジェクトを空にすることもできます:


let person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

person = undefined;
// これで値と型の両方がundefinedになります

undefinedとnullの違い

undefinedとnullは値としては等価ですが、型としては異なります:


typeof undefined      // undefinedを返す
typeof null           // objectを返す

null === undefined    // false
null == undefined     // true

constructorプロパティ

constructorプロパティは、すべてのJavaScript変数のコンストラクタ関数を返します。


// function Object() {[native code]}を返します:
{name:'John',age:34}.constructor

// function Array() {[native code]}を返します:
[1,2,3,4].constructor

// function Date() {[native code]}を返します:
new Date().constructor

// function Set() {[native code]}を返します:
new Set().constructor

// function Map() {[native code]}を返します:
new Map().constructor

// function Function() {[native code]}を返します:
function () {}.constructor

constructorを使用すると、オブジェクトが配列かどうかを確認できます:


(myArray.constructor === Array);

また、constructorを使用してオブジェクトが日付かどうかも確認できます:


(myDate.constructor === Date);

全体をまとめると


typeof "John"          // "string"を返す
typeof ("John"+"Doe")  // "string"を返す
typeof 3.14            // "number"を返す
typeof (33 + 66)       // "number"を返す
typeof NaN             // "number"を返す
typeof 1234n           // "bigint"を返す
typeof true            // "boolean"を返す
typeof false           // "boolean"を返す
typeof {name:'John'}   // "object"を返す
typeof [1,2,3,4]       // "object"を返す
typeof {}              // "object"を返す
typeof []              // "object"を返す
typeof new Object()    // "object"を返す
typeof new Array()     // "object"を返す
typeof new Date()      // "object"を返す
typeof new Set()       // "object"を返す
typeof new Map()       // "object"を返す
typeof function () {}  // "function"を返す
typeof x               // "undefined"を返す
typeof null            // "object"を返す

Note:

NaN(NaN)のデータ型は”number”です!

void演算子

void演算子は式を評価し、undefinedを返します。この演算子は、”void(0)”を使用して未使用の返り値を評価する場合に便利です。


<a href="javascript:void(0);">
  リンクをクリックしてください
</a>

<a href="javascript:void(document.body.style.backgroundColor='red');">
  ボディの背景色を赤に変更するためにクリックしてください
</a>

new Map()メソッド

new Map()コンストラクタに配列を渡すことでMapを作成できます:


// Mapを作成する
const fruits = new Map([
  ["apples", 500],
  ["bananas", 300],
  ["oranges", 200]
]);

Map.get()

get()メソッドを使用して、Map内の特定のキーの値を取得できます:


fruits.get("apples");

Map.set()

set()メソッドを使用して、Mapに要素を追加できます:


// Mapを作成する
const fruits = new Map();

// Mapの値を設定する
fruits.set("apples", 500);
fruits.set("bananas", 300);
fruits.set("oranges", 200);

set()メソッドは既存のMapの値を変更するのにも使用できます:


fruits.set("apples", 500);

Map.size

sizeプロパティはMap内の要素数を返します:


fruits.size;

Map.delete()

delete()メソッドは指定されたキーの要素を削除します:


fruits.delete("apples");

Map.clear()

clear()メソッドはMapからすべての要素を削除します:


fruits.clear();

Map.has()

has()メソッドは指定されたキーがMap内に存在する場合にtrueを返します:


fruits.has("apples");

Try This:


fruits.delete("apples");
fruits.has("apples");

Map.forEach()

forEach()メソッドはMap内の各キー/値ペアに対してコールバックを呼び出します:


// すべてのエントリをリストアップする
let text = "";
fruits.forEach (function(value, key) {
  text += key + ' = ' + value;
})

Map.entries()

entries()メソッドはMap内の[key, value]ペアを持つイテレータオブジェクトを返します:


// すべてのエントリをリストアップする
let text = "";
for (const x of fruits.entries()) {
  text += x;
}

Map.keys()

keys()メソッドはMap内のキーを持つイテレータオブジェクトを返します:


// すべてのキーをリストアップする
let text = "";
for (const x of fruits.keys()) {
  text += x;
}

Map.values()

values()メソッドはMap内の値を持つイテレータオブジェクトを返します:


// すべての値をリストアップする
let text = "";
for (const x of fruits.values()) {
  text += x;
}

values()メソッドを使用してMap内の値を合計することができます:


// すべての値を合計する
let total = 0;
for (const x of fruits.values()) {
  total += x;
}

キーとしてのオブジェクト

オブジェクトをキーとして使用できることはMapの重要な機能です。


// オブジェクトを作成する
const apples = {name: 'Apples'};
const bananas = {name: 'Bananas'};
const oranges = {name: 'Oranges'};

// Mapを作成する
const fruits = new Map();

// Mapに新しい要素を追加する
fruits.set(apples, 500);
fruits.set(bananas, 300);
fruits.set(oranges, 200);

注意:キーはオブジェクト(apples)であり、文字列(”apples”)ではありません:


fruits.get("apples");  // undefinedを返す

JavaScript Map.groupBy()

ES2024ではJavaScriptにMap.groupBy()メソッドが追加されました。

Map.groupBy()メソッドは、コールバック関数から返される文字列値に従ってオブジェクトの要素をグループ化します。

Map.groupBy()メソッドは、元のオブジェクトを変更しません。


// 配列を作成する
const fruits = [
  {name:"apples", quantity:300},
  {name:"bananas", quantity:500},
  {name:"oranges", quantity:200},
  {name:"kiwi", quantity:150}
];

// 要素をグループ化するためのコールバック関数
function myCallback({ quantity }) {
  return quantity > 200 ? "ok" : "low";
}

// 数量でグループ化
const result = Map.groupBy(fruits, myCallback);

注意

ES2024の機能は比較的新しいものです。

古いブラウザでは代替コード(Polyfill)が必要な場合があります。

Object.groupBy() vs Map.groupBy()

Object.groupBy()とMap.groupBy()の違い:

Mapはキーと値のペアを保持し、キーは任意のデータ型になります。

Mapはキーの挿入順序を覚えています。

Mapの作成方法

JavaScriptのMapを作成する方法:

new Map()メソッド

new Map()コンストラクタに配列を渡すことでMapを作成できます:


// Mapを作成する
const fruits = new Map([
  ["apples", 500],
  ["bananas", 300],
  ["oranges", 200]
]);

set()メソッド

set()メソッドを使ってMapに要素を追加できます:


// Mapを作成する
const fruits = new Map();

// Mapの値を設定する
fruits.set("apples", 500);
fruits.set("bananas", 300);
fruits.set("oranges", 200);

set()メソッドは既存のMapの値を変更するのにも使用できます:


fruits.set("apples", 200);

get()メソッド

get()メソッドはMap内のキーの値を取得します:


fruits.get("apples");    // 500を返す

Mapはオブジェクトです

typeofはオブジェクトを返します:


typeof fruits;    // オブジェクトを返す

instanceof Mapはtrueを返します:


fruits instanceof Map;    // trueを返す

JavaScriptのオブジェクト vs Map

JavaScriptのオブジェクトとMapの違い:

オブジェクト Map
直接的にはイテラブルではない 直接的にはイテラブル
サイズプロパティを持たない サイズプロパティを持つ
キーは文字列(またはシンボル)である必要がある キーは任意のデータ型になり得る
キーの順序は定義されていない キーは挿入の順序で保持される
デフォルトのキーを持たない デフォルトのキーを持つ