History: pushState() メソッド - Web API

History: pushState() メソッド
=========================

HTML 文書では、 **`history.pushState()`** メソッドはブラウザーのセッション履歴スタックに項目を追加します。

このメソッドは非同期です。移動が完了したときを検知したい場合は `popstate` イベントのリスナーを追加してください。

構文
--

```js
pushState(state, unused)
pushState(state, unused, url)
```

### 引数

`state`

この `state` (状態)オブジェクトは、`pushState()` によって作られる新しい履歴項目に関連した JavaScript オブジェクトです。ユーザーが新規の `state` に移動したときはいつも、 `popstate` イベントが発行され、イベントの `state` プロパティは、履歴項目の `state` オブジェクトのコピーを含みます。

`state` オブジェクトは、シリアライズ可能なあらゆものとなりえます。 Firefox では状態オブジェクトをユーザーのディスクに保存してブラウザーを再起動した後にも復帰できるため、 `state` オブジェクトのシリアライズ表現に 16 MiB の上限を課しています。これを超える大きさの状態オブジェクトを `pushState()` に渡した場合、このメソッドで例外が発生します。これ以上のスペースが必要な場合、`sessionStorage` や `localStorage` を使用することをお勧めします。

`unused`

この引数は歴史的な理由のために存在しており、省略することはできません。空文字を渡すことが、将来このメソッドに変更が加えられたときに安全です。

`url` 省略可

新しい履歴項目の URL は、この引数で与えられます。ブラウザーは `pushState()` を呼び出した後もこの URL を読み込もうとせずに、例えばユーザーがブラウザーを再起動した後など、後で URL を読み込む場合もあるのにご注意ください。新しい URL は絶対パスとは限りません。つまり相対パスの場合、現在の URL から相対的に解決されます。新しい URL は現在の URL と同一オリジンでなければならず、そうでない場合、`pushState()` で例外が発生します。この引数が指定されなかった場合、この文書の現在の URL が設定されます。

### 返値

なし (`undefined`)。

解説
--

 ある意味で、 `pushState()` の呼び出しは `window.location = "#foo"` と似ていて、両方とも現在の文書に関連した別の履歴項目を作成し、有効化します。
 しかし `pushState()` にはいくつかの利点があります。

* 新しい URL は現在の URL と同一オリジンにあるあらゆる URL にすることができます。それに対して、`window.location` に設定した場合、ハッシュのみを変更したのであれば同じ文書にとどまります。
* URL を変更することは必須ではありません。それに対して、 `window.location = "#foo";` を設定する場合は、現在のハッシュが `#foo` でない場合のみ新規の履歴項目を作成します。
* 履歴項目に任意のデータを関連づけることができます。ハッシュベースのアプローチでは、関連するデータすべてを短い文字列にエンコードする必要があります。

`pushState()` は `hashchange` イベントを発行しません。新 URL が旧 URL とハッシュだけ異なる場合でもそうなることに気をつけてください。

例
-

これはブラウザーの履歴項目に *state* と *url* を設定したものを作成します。

### JavaScript

```js
const state = { page\_id: 1, user\_id: 5 };
const url = "hello-world.html";

history.pushState(state, "", url);
```

### クエリー引数の変更

```js
const url = new URL(location);
url.searchParams.set("foo", "bar");
history.pushState({}, "", url);
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-pushstate-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* 履歴 API の操作
* Window: popstate イベント


History: state プロパティ - Web API

History: state プロパティ
====================

**`History.state`** プロパティは、履歴スタックの一番上の状態を表す値を返します。これは `popstate` イベントを待つことなく、状態を見ることができる方法です。

値
-

履歴スタックの一番上の状態です。この値は `pushState()` または `replaceState()` メソッドが使用されていない限り `null` です。

例
-

 以下のコードでは、 `history.state` の値を `pushState()` メソッドを使用して値を履歴にプッシュする前に、ログに記録しています。
 次の行では、再びコンソールに値が記録され、 `history.state` に値があることが分かります。

```js
// まだ履歴スタックを変更していないため、 null になります
console.log("History.state before pushState: ", history.state);

// スタックに何かプッシュします
history.pushState({ name: "Example" }, "pushState example", "page3.html");

// 状態は値になりました。
console.log("History.state after pushState: ", history.state);
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-state-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* 履歴 API での作業
* `History.pushState()`
* `History.replaceState()`
* `PopStateEvent.state`


History: length プロパティ - Web API

History: length プロパティ
=====================

**`History.length`** は読み取り専用のプロパティで、セッション履歴に含まれる要素の数を、現在読み込まれているページを含めて表す整数を返します。

例えば、新しいタブに読み込まれたページでは、このプロパティは `1` を返します。

値
-

数値です。

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-length-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* 所属先の `History` インターフェイス


History: replaceState() メソッド - Web API

History: replaceState() メソッド
============================

**`History.replaceState()`** メソッドは、現在の履歴を編集し、メソッドに引数で渡された状態オブジェクトや URL で置き換えます。このメソッドは、ユーザーのアクションに応じて現在の履歴項目の状態オブジェクトや URL を更新したい場合に特に便利です。

このメソッドは非同期です。移動が完了したときを検知したい場合は `popstate` イベントのリスナーを追加してください。

構文
--

```js
replaceState(state, unused)
replaceState(state, unused, url)
```

### 引数

`state`

オブジェクトで、 `replaceState` メソッドに渡された履歴項目に関連付けられます。状態オブジェクトは `null` を指定することができます。

`unused`

この引数は歴史的な理由のために存在しており、省略することはできません。空文字を渡すことが、将来このメソッドに変更が加えられたときに安全です。

`url` 省略可

履歴項目の URL です。新しい URL は現在の URL と同じオリジンでなければなりません。もしそうでないと、 replaceState で例外が発生します。

### 返値

なし (`undefined`)。

例
-

`https://www.mozilla.org/foo.html` が以下の JavaScript を実行したとします。

```js
const stateObj = { foo: "bar" };
history.pushState(stateObj, "", "bar.html");
```

次のページでは、 `history.state` を使用して、追加したばかりの `stateObj` にアクセスすることができます。

上記の 2 行の説明は、履歴 API での作業の記事の `pushState()` の例にあります。次に、 `https://www.mozilla.org/bar.html` が以下の JavaScript を実行したとします。

```js
history.replaceState(stateObj, "", "bar2.html");
```

これにより、URL バーに `https://www.mozilla.org/bar2.html` が表示されるようになりますが、ブラウザーが `bar2.html` を読み込んだり、`bar2.html` が存在するかどうかを確認したりすることはありません。

ユーザーが `https://www.microsoft.com` に移動し、戻るボタンをクリックしたとします。この時点で、URL バーには `https://www.mozilla.org/bar2.html` が表示されます。ユーザーがもう一度「戻る」ボタンをクリックすると、URL バーには `https://www.mozilla.org/foo.html` が表示され、 bar.html は完全にバイパスされます。

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-replacestate-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


History: back() メソッド - Web API

History: back() メソッド
====================

**`History.back()`** メソッドは、ブラウザーにセッション履歴内で 1 つ前のページに戻らせます。

これは `history.go(-1)` を呼び出すのと同じ効果があります。 1 つ前のページがない場合、このメソッド呼び出しは何もしません。

このメソッドは非同期です。移動が完了したときを検知したい場合は `popstate` イベントのリスナーを追加してください。

構文
--

```js
back()
```

### 引数

なし。

### 返値

なし (`undefined`)。

例
-

以下の短い例では、ページ上のボタンを押すとセッション履歴内の 1 つ前の項目に移動します。

### HTML

```html
<button id="go-back">Go back!</button>
```

### JavaScript

```js
document.getElementById("go-back").addEventListener("click", () => {
  history.back();
});
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-back-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `History`
* 履歴 API の操作


History: scrollRestoration プロパティ - Web API

History: scrollRestoration プロパティ
================================

**`scrollRestoration`** は `History` インターフェイスのプロパティで、ウェブアプリケーションが履歴の移動の動作で既定のスクロール位置の復元を明示的に設定できるようにします。

値
-

以下のうちのいずれかです。

`auto`

ユーザーがスクロールしたページ上のスクロールの位置が復元されます。

`manual`

ページ上のスクロール位置は復元されません。ユーザーが手動でその位置までスクロールする必要があります。

例
-

### 現在のスクロール復元の動作を問い合わせる

```js
const scrollRestoration = history.scrollRestoration;
if (scrollRestoration === "manual") {
  console.log(
    "ページ上の位置は復元されないので、ユーザーが手動でスクロールする必要があります。",
  );
}
```

### 自動的にページ上の位置の復元をしないようにする

```js
if (history.scrollRestoration) {
  history.scrollRestoration = "manual";
}
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-scroll-restoration-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


History: forward() メソッド - Web API

History: forward() メソッド
=======================

**`History.forward()`** メソッドにより、ブラウザーはセッション履歴の 1 つ次のページに移動します。これは `history.go(1)` を呼び出すのと同じ効果があります。

このメソッドは非同期です。移動が完了したことを検知したい場合は `popstate` イベントのリスナーを追加してください。

構文
--

```js
forward()
```

### 引数

なし。

### 返値

なし (`undefined`)。

例
-

以下の例では、セッション履歴の 1 つ次のステップへ進めるボタンを作成します。

### HTML

```html
<button id="go-forward">Go Forward!</button>
```

### JavaScript

```js
document.getElementById("go-forward").addEventListener("click", (e) => {
  history.forward();
});
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-forward-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `History`
* `popstate`
* 履歴 API の操作


History: go() メソッド - Web API

History: go() メソッド
==================

**`History.go()`** メソッドは、セッション履歴から特定のページを読み込みます。これを用いると、引数の値に応じて履歴の中を前方や後方に移動することができます。

このメソッドは非同期です。移動が完了したときを検知したい場合は `popstate` イベントのリスナーを追加してください。

構文
--

```js
go()
go(delta)
```

### 引数

`delta` 省略可

履歴の中を移動したい先の位置で、現在のページからの相対位置です。負の数の場合は前方に移動し、正の値の場合は後方へ移動します。すなわち、例えば、 `history.go(2)` は 2 ページ後に移動し、 `history.go(-2)` は 2 ページ前に戻ります。値が渡されなかったときや、 `delta` が 0 と等しいときは、 `location.reload()` の呼び出しと同じ効果になります。

### 返値

なし (`undefined`)。

例
-

1 つページを戻す場合 (`back()` の呼び出しと同等)

```js
history.go(-1);
```

1 つページを進める場合、 `forward()` の呼び出しと同等です。

```js
history.go(1);
```

2 つページを進める場合

```js
history.go(2);
```

2 つページを戻す場合

```js
history.go(-2);
```

そして、以下の文はいずれも現在のページを再読み込みします。

```js
history.go();
history.go(0);
```

仕様書
---

| Specification |
| --- |
| HTML Standard # dom-history-go-dev |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `History`
* `back()`
* `forward()`
* `popstate` イベント
* 履歴 API の操作


CSSUnparsedValue: length プロパティ - Web API

CSSUnparsedValue: length プロパティ
==============================

**`length`** は `CSSUnparsedValue` インターフェイスの読み取り専用プロパティで、オブジェクト内の項目数を返します。

値
-

整数です。

例
-

この例では、`CSSUnparsedValue()` コンストラクターを使用したあと、長さを照会しています。

```js
const values = new CSSUnparsedValue(["1em", "#445566", "-45px"]);

console.log(values.length); // 3
```

仕様書
---

| Specification |
| --- |
| CSS Typed OM Level 1 # dom-cssunparsedvalue-length |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue()`
* `CSSUnparsedValue.entries`
* `CSSUnparsedValue.forEach`
* `CSSUnparsedValue.keys`
* `CSSUnparsedValue.values`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


CSSUnparsedValue: CSSUnparsedValue() コンストラクター - Web API

CSSUnparsedValue: CSSUnparsedValue() コンストラクター
=============================================

**`CSSUnparsedValue()`** はコンストラクターで、カスタムプロパティのプロパティ値を表す新しい `CSSUnparsedValue` オブジェクトを生成します。

構文
--

```js
new CSSUnparsedValue(members)
```

### 引数

`members`

文字列または `CSSVariableReferenceValue` のどちらかの値を持つ配列です。

例
-

```js
const value = new CSSUnparsedValue(["4deg"]);
const values = new CSSUnparsedValue(["1em", "#445566", "-45px"]);

console.log(value); // CSSUnparsedValue {0: "4deg", length: 1}
console.log(values); // CSSUnparsedValue {0: "1em", 1: "#445566", 2: "-45px", length: 3}
```

仕様書
---

| Specification |
| --- |
| CSS Typed OM Level 1 # dom-cssunparsedvalue-cssunparsedvalue |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue.entries`
* `CSSUnparsedValue.forEach`
* `CSSUnparsedValue.keys`
* `CSSUnparsedValue.length`
* `CSSUnparsedValue.values`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


CSSUnparsedValue: values() メソッド - Web API

CSSUnparsedValue: values() メソッド
===============================

**`CSSUnparsedValue.values()`** メソッドは、 CSSUnparsedValue オブジェクト内のそれぞれの添字の値を持つ新しい配列イテレーターオブジェクトを返します。

構文
--

```js
values()
```

### 引数

なし。

### 返値

新しい `Array`。

仕様書
---

#### No specification found

No specification data found for `api.CSSUnparsedValue.values`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue()`
* `CSSUnparsedValue.entries`
* `CSSUnparsedValue.forEach`
* `CSSUnparsedValue.keys`
* `CSSUnparsedValue.length`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


CSSUnparsedValue: keys() メソッド - Web API

CSSUnparsedValue: keys() メソッド
=============================

**`CSSUnparsedValue.keys()`** メソッドは、配列内のそれぞれの添字のキーを持つ新しい配列イテレーターオブジェクトを返します。

構文
--

```js
keys()
```

### 引数

なし。

### 返値

新しい `Array`。

仕様書
---

#### No specification found

No specification data found for `api.CSSUnparsedValue.keys`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue()`
* `CSSUnparsedValue.entries`
* `CSSUnparsedValue.forEach`
* `CSSUnparsedValue.length`
* `CSSUnparsedValue.values`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


CSSUnparsedValue: forEach() メソッド - Web API

CSSUnparsedValue: forEach() メソッド
================================

**`CSSUnparsedValue.forEach()`** メソッドは、指定された関数を、`CSSUnparsedValue` オブジェクトのそれぞれの要素に対して実行します。

構文
--

```js
forEach(callbackFn)
forEach(callbackFn, thisArg)
```

### 引数

`callbackFn`

それぞれの要素について呼び出される関数で、3 つの引数を取ります。

`currentValue`

処理中の現在の要素の値。

`index` 省略可

処理中の現在の要素の添字。

`array` 省略可

`forEach()` が呼び出されている `CSSUnparsedValue`。

`thisArg` 省略可

`callback` の実行中に、 **`this`** として使用する値（つまり、`Object` の参照）。.

### 返値

なし (`undefined`)。

仕様書
---

#### No specification found

No specification data found for `api.CSSUnparsedValue.forEach`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue()`
* `CSSUnparsedValue.entries`
* `CSSUnparsedValue.keys`
* `CSSUnparsedValue.length`
* `CSSUnparsedValue.values`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


CSSUnparsedValue: entries() メソッド - Web API

CSSUnparsedValue: entries() メソッド
================================

**`CSSUnparsedValue.entries()`** メソッドは、指定されたオブジェクトの列挙可能なプロパティ `[key, value]` の組の配列を、`for...in` ループで提供されるのと同じ順序で返します（違いは for-in ループがプロトタイプチェーン上のプロパティも列挙することです）。

構文
--

```js
entries(obj)
```

### 引数

`obj`

`CSSUnparsedValue` で、列挙可能な固有のプロパティの `[key, value]` の組を返します。

### 返値

指定された `CSSUnparsedValue` の配列で、列挙可能な固有のプロパティの `[key, value]` の組。

仕様書
---

#### No specification found

No specification data found for `api.CSSUnparsedValue.entries`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnparsedValue()`
* `CSSUnparsedValue.forEach`
* `CSSUnparsedValue.keys`
* `CSSUnparsedValue.length`
* `CSSUnparsedValue.values`
* CSS 型付きオブジェクトモデルの使用
* CSS 型付きオブジェクトモデル API


IndexedDB の使用 - Web API

IndexedDB の使用
=============

IndexedDB は、ユーザーのブラウザー内にデータを永続的に保存する手段です。ネットワークの状態にかかわらず高度な問い合わせ機能を持つウェブアプリケーションを作成できますので、アプリケーションがオンラインとオフラインの両方で動作するようになります。

この記事について
--------

このチュートリアルでは、IndexedDB の非同期 API の使い方を見ていきます。IndexedDB について詳しくない場合は、始めに IndexedDB の主な特徴と基本用語をお読みください。

IndexedDB API のリファレンスドキュメントとして、IndexedDB API の記事とそのサブ記事をご覧ください。この記事では、IndexedDB で使用されるオブジェクトの種類と、非同期 API のメソッドについて説明します (同期 API は仕様から削除されました)。

基本パターン
------

IndexedDB で推奨される基本パターンは、以下のようになります。

1. データベースを開きます。
2. データベース内に、オブジェクトストアを作成します。
3. データの追加や取り出しといった、データベース操作のトランザクションを開始して、リクエストを行います。
4. 適切な DOM イベントを受け取ることにより、操作が完了するのを待ちます。
5. 結果 (リクエストオブジェクトにある) に応じた処理を行います。

これらの主要な概念を踏まえることで、より具体的な手続きを理解できます。

ストアを作成および構築する
-------------

### データベースを開く

プロセス全体は以下のようにして始めます。

```js
// データベースを開く
const request = window.indexedDB.open("MyTestDatabase", 3);
```

わかりますか? データベースを開くことも他の操作と同様であり、「リクエスト」が必要です。

データベースを開くリクエストは、すぐにはデータベースを開いたりトランザクションを開始したりはしません。`open()` 関数を呼び出すと、結果 (成功) またはイベントとして扱うエラー値を伴う `IDBOpenDBRequest` オブジェクトを返します。IndexedDB のほとんどの他の非同期関数も同様であり、結果またはエラーを伴う `IDBRequest` オブジェクトを返します。open 関数の結果は `IDBDatabase` のインスタンスです。

open メソッドの第 2 引数は、データベースのバージョンです。データベースのバージョンは、データベースのスキーマ、すなわちデータベース内のオブジェクトストアとその構造を決定します。データベースが存在しない場合に `open` 操作でデータベースが作成されると、`onupgradeneeded` イベントが発生し、そのイベントハンドラーでデータベースのスキーマを作成することができます。データベースが存在する場合に従来より高いバージョン番号を指定すると、すぐに `onupgradeneeded` イベントが発生して、そのイベントハンドラーで更新されたスキーマを提供することができます。詳しくは、後ほどデータベースのバージョンの作成と更新で説明します。また、 `IDBFactory.open` のリファレンスページもご覧ください。

**警告:** バージョン番号は `unsigned long long` 型の数値であり、とても大きい整数にすることができます。また浮動小数点数値は使用できず、使用した場合は `upgradeneeded` イベントが発生せず、もっとも近い小さな数値に変換されてトランザクションが始まるでしょう。よって、例えばバージョン番号として 2.4 を使用しないでください。
 `const request = indexedDB.open("MyTestDatabase", 2.4); // 行ってはいけません。バージョンは 2 に丸められます`

#### ハンドラーの生成

ほぼすべてのリクエスト生成に合わせて始めに行いたいことは、成功およびエラーのハンドラーを生成することでしょう。

```js
request.onerror = (event) => {
  // request.errorCode に対して行うこと!
};
request.onsuccess = (event) => {
  // request.result に対して行うこと!
};
```

2 つの関数 `onsuccess()` と `onerror()` のどちらが呼び出されるのでしょう? すべてが成功すると成功イベント (すなわち `type` プロパティが `"success"` である DOM イベント) が、`request` を `target` として発生します。イベントが発生すると `request` の `onsuccess()` 関数が、success イベントを引数として呼び出されます。一方、何らかの問題がある場合はエラーイベント (すなわち `type` プロパティが `"error"` である DOM イベント) が `request` で発生します。これは、エラーイベントを引数として `onerror()` 関数を呼び出します。

IndexedDB API は必要なエラー処理を最小限にするよう設計されていますので、多くのエラーイベントを見ることはないでしょう (少なくとも、API に慣れていなければ)。しかしデータベースを開く場合は、エラーイベントが発生する一般的な状況があります。もっとも多いであろう問題は、データベースを作成する許可をユーザーがウェブアプリに与えなかったことです。IndexedDB の主要な設計目標のひとつが、オフラインで使用するために大量のデータを保存できるようにすることです。(各ブラウザーでどれだけの量のストレージを持てるかについては、ストレージの制限をご覧ください)

広告ネットワークやコンピューターを汚染させる悪意のあるウェブサイトをブラウザーが許可したくないことは明らかですので、ブラウザーは ウェブアプリが初めてストレージ用に IndexedDB を開こうとしたときに、ユーザーへプロンプトを表示します。ユーザーはアクセスを許可または拒否できます。またブラウザーのプライバシーモードでの IndexedDB ストレージは、匿名のセッションを閉じるまでの間だけメモリー上に存在します (Firefox のプライベートブラウジングモードや Chrome のシークレットモードのことですが、2021 年 5 月現在の Firefox ではこれが未実装ですので、Firefox のプライベートブラウジングでは IndexedDB をまったく使用できません)。

ユーザーがデータベース作成の要求を許可して、成功コールバックを実行する成功イベントを受け取ったと想定します。次は何を行うのでしょうか? 以下のリクエストは `indexedDB.open()` の呼び出しを伴って生成されており、`request.result` は `IDBDatabase` のインスタンスですので、以降のためにこれを保存したいことは確実です。よって、コードは以下のようになるでしょう。

```js
let db;
const request = indexedDB.open("MyTestDatabase");
request.onerror = (event) => {
  console.error(
    "なぜ私の ウェブアプリで IndexedDB を使わせてくれないのですか?!",
  );
};
request.onsuccess = (event) => {
  db = event.target.result;
};
```

#### エラーを処理する

前述のとおり、エラーイベントはバブリングします。エラーイベントはエラーを発生させたリクエストをターゲットにして、さらにトランザクションや最終的にデータベースオブジェクトへバブリングします。すべてのリクエストにエラーハンドラーを追加することを避けたい場合は、代わりに以下のように、ひとつのエラーハンドラーをデータベースオブジェクトに追加することができます。

```js
db.onerror = (event) => {
  // このデータベースのリクエストに対するすべてのエラー用の
  // 汎用エラーハンドラー!
  console.error(`Database error: ${event.target.errorCode}`);
};
```

データベースを開く際によく発生するエラーのひとつが `VER_ERR` です。これはディスクに保存されているデータベースのバージョンが、開こうとしているバージョンより*大きい*ことを表します。これは、必ずエラーハンドラーで処理しなければならないエラーの実例です。

### データベースのバージョンの作成と更新

新しいデータベースを作成したり既存のデータベースのバージョンを更新したりする (データベースを開く際に、従来より大きなバージョン番号を指定する) と `onupgradeneeded` イベントが発生して、`request.result` (すなわち、以下の例の `db`) に設定した `onversionchange` イベントハンドラーに IDBVersionChangeEvent オブジェクトが渡されます。`upgradeneeded` イベントのハンドラーでは、このバージョンのデータベースで必要なオブジェクトストアを作成します。

```js
// このイベントは最新のブラウザーにのみ実装されています
request.onupgradeneeded = (event) => {
  // IDBDatabase インターフェイスに保存します
  const db = event.target.result;

  // このデータベース用の objectStore を作成します
  const objectStore = db.createObjectStore("name", { keyPath: "myKey" });
};
```

この場合、データベースは旧バージョンのデータベース由来のオブジェクトストアをすでに持っていますので、それらのオブジェクトストアを再作成する必要はありません。新しいオブジェクトストアを作成するか、不要になった旧バージョンのオブジェクトストアを削除することだけが必要です。既存のオブジェクトストアを変更しなければならない (例えば `keyPath` を変更する) 場合は、古いオブジェクトストアを削除してから、新たな設定で再作成しなければならりません。(これはオブジェクトストア内の情報を削除しますので注意してください! この情報を保存しなければならない場合は、データベースをアップグレードする前にデータを読み出して、別の場所に保存してください)

既存の名称を使用してオブジェクトストアを作成しようとする (あるいは、存在しない名称のオブジェクトストアを削除しようとする) と、エラーが発生します。

`onupgradeneeded` イベントから正常に抜けた場合は、データベースを開くリクエストの `onsuccess` ハンドラーが実行されます。

### データベースを構築する

次に、データベースを構築します。IndexedDB はテーブルではなくオブジェクトストアを使用しており、ひとつのデータベースに複数のオブジェクトストアを含めることができます。値をオブジェクトストアへ保存するたびに、値がキーと関連付けられます。オブジェクトストアでキーパスを使用するかキージェネレーターを使用するかに応じて、キーを供給する方法がいくつか存在します。

以下の表で、キーを供給するさまざまな方法を示します。

| キーパス (`keyPath`) | キージェネレーター (`autoIncrement`) | 説明 |
| --- | --- | --- |
| なし | なし | このオブジェクトストアは、数値や文字列といったプリミティブ値を含む、どのような種類の値でも保持できます。新たな値の追加を望むたびに、個別のキー引数を供給しなければなりません。 |
| あり | なし | このオブジェクトストアは、JavaScript オブジェクトのみ保持できます。オブジェクトはキーパスと同じ名称のプロパティを持たなければなりません。 |
| なし | あり | このオブジェクトストアは、どのような種類の値でも保持できます。キーは自動的に生成されます。また、特定のキーを使用したい場合は個別のキー引数を供給できます。 |
| あり | あり | このオブジェクトストアは、JavaScript オブジェクトのみ保持できます。通常はキーが生成されて、オブジェクトでキーパスと同じ名称を持つプロパティに、生成されたキーの値を保存します。ただしそのようなプロパティがすでに存在している場合は、生成された新たなキーではなく、そのプロパティの値をキーとして使用します。 |

オブジェクトストアがプリミティブではなくオブジェクトを保持していれば、オブジェクトストアでインデックスを作成することもできます。インデックスは、オブジェクトのキーではなく保存されたオブジェクトのプロパティの値を使用して、オブジェクトストア内に保存された値を検索することを可能にします。

さらにインデックスには、保存されたデータに単純な制限を強制する機能があります。インデックスを作成する際に unique フラグを設定すると、インデックスのキーパスで同じ値を持つオブジェクトが複数保存されないことを、インデックスが保証します。よって例えば人々の集団の情報を保持するオブジェクトストアがある場合に、同じメールアドレスを持つ人が 2 人存在しないことを保証したい場合は、これを強制するために unique フラグを設定したインデックスを使用するとよいでしょう。

これには混乱するかもしれませんので、シンプルな例で概念を説明するべきでしょう。始めに、例で使用する顧客データをいくつか定義します。

```js
// 顧客データがどのようなものかを示します
const customerData = [
  { ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
  { ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" },
];
```

もちろん、誰かの社会保障番号を顧客テーブルの主キーとして使用するべきではないですし (社会保障番号を持っていない人もいます)、年齢の代わりに誕生日を保管することもできますが、これらの不適切な選択は利便性のために無視して先へ進みましょう。

次に、データを保存する IndexedDB を作成するところを見てみましょう。

```js
const dbName = "the\_name";

const request = indexedDB.open(dbName, 2);

request.onerror = (event) => {
  // エラー処理
};
request.onupgradeneeded = (event) => {
  const db = event.target.result;

  // 顧客の情報を保存する objectStore を作成します。
  // "ssn" は一意であることが保証されています - 少なくとも、キックオフミーティングで
  // そのように言われました。なので、キーパスとして使用します。
  const objectStore = db.createObjectStore("customers", { keyPath: "ssn" });

  // 顧客を名前で検索するためのインデックスを作成します。
  // 重複する可能性がありますので、一意のインデックスとしては使用できません。
  objectStore.createIndex("name", "name", { unique: false });

  // 顧客をメールアドレスで検索するためのインデックスを作成します。2 人の顧客が同じメールアドレスを
  // 使用しないようにしたいので、一意のインデックスを使用します。
  objectStore.createIndex("email", "email", { unique: true });

  // データを追加する前に objectStore の作成を完了させるため、
  // transaction oncomplete を使用します。
  objectStore.transaction.oncomplete = (event) => {
    // 新たに作成した objectStore に値を保存します。
    const customerObjectStore = db
      .transaction("customers", "readwrite")
      .objectStore("customers");
    customerData.forEach((customer) => {
      customerObjectStore.add(customer);
    });
  };
};
```

先に示したように、`onupgradeneeded` はデータベースの構造を変えることができる唯一の場所です。ここではオブジェクトストアの作成および削除や、インデックスの構築および削除が可能です。

オブジェクトストアは `createObjectStore()` を 1 回呼び出して作成します。このメソッドの引数は、ストアの名前と引数オブジェクトです。引数オブジェクトは省略可能ですが、重要なオプションプロパティを定義したり、作成したいオブジェクトストアの型を改良することができますので、とても重要です。この例では "customers" という名前のオブジェクトストアを要求して、`keyPath` を定義しています。`keyPath` は、ストア内で個々のオブジェクトを一意にするプロパティです。この例では、社会保障番号が一意であることが保証されていますので "ssn" にしています。"ssn" は、`objectStore` に保存するすべてのオブジェクトに与えなければなりません。

また、保存されたオブジェクトの `name` プロパティを参照する、"name" という名前のインデックスも要求しています。`createObjectStore()` と同様に `createIndex()` も、作成したいインデックスの型を改良するための省略可能な引数 `options` オブジェクトを指定できます。`name` プロパティを持たないオブジェクトを追加することはできますが、そのオブジェクトは "name" インデックス内に現れません。

以上でオブジェクトストアに保存された顧客オブジェクトを、`ssn` を使用して直接、またはインデックスを使用して名前をもとにして、取り出すことができます。この仕組みについて詳しくは、インデックスの使用をご覧ください。

### キージェネレーターを使用する

オブジェクトストアを作成するときに `autoIncrement` フラグを設定すると、そのオブジェクトストアでキージェネレーターを使用できます。デフォルトで、このフラグは設定されません。

キージェネレーターを使用すると、オブジェクトストアに値を追加するのに応じて自動的にキーが生成されます。オブジェクトストアでキージェネレーターを初めて作成した時点では、キージェネレーターの値が常に 1 になります。基本的に、新たに自動生成されるキーは、前のキーから 1 増加した値になります。データベースのトランザクションが中止されるなど、データベースの操作が取り消された場合を除き、キージェネレーターの現在の値が減少することはありません。従って、オブジェクトストアからレコードを削除したりすべてのレコードをクリアしたりしても、オブジェクトストアのキージェネレーターには影響がありません。

以下のように、キージェネレーターを持つ別のオブジェクトストアを作成できます。

```js
// indexedDB を開きます。
const request = indexedDB.open(dbName, 3);

request.onupgradeneeded = (event) => {
  const db = event.target.result;

  // autoIncrement フラグに true を設定した、"names" という名前のオブジェクトストアを作成します。
  const objStore = db.createObjectStore("names", { autoIncrement: true });

  // "names" オブジェクトストアはキージェネレーターを持っていますので、値 name のキーは自動的に生成されます。
  // 追加したレコードは以下のようになります:
  // キー : 1 => 値 : "Bill"
  // キー : 2 => 値 : "Donna"
  customerData.forEach((customer) => {
    objStore.add(customer.name);
  });
};
```

キージェネレーターについて詳しくは、"W3C Key Generators" をご覧ください。

データの追加、読み取り、削除
--------------

新しいデータベースで何かを行えるようにする前に、トランザクションを開始しなければなりません。トランザクションはデータベースオブジェクトから生じており、トランザクションの対象にしたいオブジェクトストアを指定しなければなりません。トランザクションの内部では、データを保持しているオブジェクトストアへのアクセスや、リクエストの実行が可能です。次に、データベースに変更処理を行うのか、あるいはデータベースから読み出すだけかを決めなければなりません。トランザクションは `readonly`、`readwrite`、`versionchange` の 3 つのモードを使用できます。

データベースの「スキーマ」や構造を変更する (オブジェクトストアやインデックスを作成または削除する) には、トランザクションを `versionchange` モードにしなければなりません。このトランザクションは、`version` を指定して `IDBFactory.open` メソッドを呼び出すことによって開きます。

既存のオブジェクトストアからレコードを読み出すには、トランザクションで `readonly` モードまたは `readwrite` モードを使用できます。既存のオブジェクトストアに変更処理を行うには、トランザクションを `readwrite` モードにしなければなりません。このようなトランザクションは `IDBDatabase.transaction` で開きます。このメソッドの引数は 2 つあり、`storeNames` (アクセスしたいオブジェクトストアの配列で定義されるスコープ) とトランザクションの `mode` (`readonly` または `readwrite`) です。またこのメソッドは、`IDBTransaction.objectStore` メソッドを持つトランザクションオブジェクトを返します。`objectStore` メソッドは、オブジェクトストアにアクセスするために使用できます。デフォルトでは、モードを指定しなければ `readonly` モードでトランザクションを開きます。

**メモ:** Firefox 40 で、IndexedDB トランザクションはパフォーマンスを向上させるために、永続性の保証を緩和しました (Firefox バグ 1112702 を参照)。以前は `readwrite` モードのトランザクションで、すべてのデータをディスク上に反映したことが保証された場合に限り `complete` 発生しました。Firefox 40 以降では OS がデータの書き込みを指示した時点で `complete` が発生しており、実際にはデータがディスク上に反映されていない可能性があります。これにより `complete` イベントをより早く発生させられますが、データをディスク上に反映する前に OS のクラッシュや電源断が発生するとトランザクション全体を失う危険性が若干あります。このような破壊的な事象はまれですので、ほとんどの利用者は心配する必要がないでしょう。何らかの理由 (例えば、後で再計算できない重要なデータを保存する) で永続性を保証しなければならない場合は、実験的 (非標準) な `readwriteflush` モード (`IDBDatabase.transaction` を参照) を使用してトランザクションを生成すると、`complete` イベントを発生させる前にディスクへの反映を強制させることができます。

トランザクションで適切なスコープおよびモードを使用すると、データアクセスを高速化できます。ヒントを 2 つ紹介します。

* スコープを定義するときは、必要なオブジェクトストアのみ指定します。これにより、同時にスコープが重なり合うことなく、複数のトランザクションを実行できます。
* `readwrite` トランザクションモードは、必要な場合に限り指定します。`readonly` トランザクションはスコープが重なっても複数同時に実行できますが、`readwrite` トランザクションはオブジェクトストアに対して 1 個しか実行できません。詳しくは、IndexedDB の主な特徴と基本用語の記事で トランザクションの定義をご覧ください。
### データベースにデータを追加する

データベースを作成したら、書き込みを行いたいと考えるでしょう。これは以下のようにします。

```js
var transaction = db.transaction(["customers"], "readwrite");
// メモ: 古い実験的な実装では、"readwrite" の代わりに非推奨の定数 IDBTransaction.READ\_WRITE を使用します。
// そのような実装をサポートしたい場合は、以下のように記述します。
// var transaction = db.transaction(["customers"], IDBTransaction.READ\_WRITE);
```

`transaction()` 関数は引数が 2 つあり (ひとつは省略可能)、トランザクションオブジェクトを返します。第 1 引数は、トランザクションの対象にするオブジェクトストアのリストです。トランザクションですべてのオブジェクトを対象にしたい場合は空の配列を渡すことができますが、仕様書では空の配列に対して `InvalidAccessError` を生成すべきとされていますので、行わないようにしてください。第 2 引数に何も指定しなければ、読み取り専用のトランザクションになります。書き込みを行いたい場合は、`"readwrite"` フラグを渡さなければなりません。

以上で、存続期間を理解しなければならないトランザクションができました。トランザクションは、イベントループととても密接に結びついています。トランザクションを作成して、それを使用せずにイベントループに戻ると、トランザクションが非アクティブ状態になります。トランザクションをアクティブにし続ける唯一の方法が、トランザクションでリクエストを行うことです。リクエストが完了すると DOM イベントが発生して、リクエストが成功したと仮定すれば、コールバックの実行中にトランザクションを拡張するもうひとつの機会を得られます。トランザクションを拡張せずにイベントループへ戻ると、トランザクションは非アクティブ状態になります。保留中のリクエストがある限り、トランザクションはアクティブであり続けます。トランザクションの存続期間はごくシンプルですが、慣れるまでには少々時間がかかるでしょう。さらにいくつかの例も、理解する助けになるでしょう。`TRANSACTION_INACTIVE_ERR` エラーコードを見始めた場合は、何らかの誤りがあるでしょう。

トランザクションは `error`、`abort`、`complete` の 3 種類の DOM イベントを受け取る可能性があります。`error` イベントがバブリングする方法について話したとおり、トランザクションは、生成したあらゆるリクエストが由来のエラーイベントを受け取ります。より細かいポイントとして、エラー時のデフォルトの動作は、エラーが発生したトランザクションを中止させることです。エラーイベントで始めに `stopPropagation()` を呼び出して、他の処理を行うようにエラー制御を行わなければ、トランザクション全体がロールバックします。この設計によってエラー制御を考えるよう強いられますが、きめ細かいエラー制御がとても複雑になる場合は、データベースに対して包括的なエラー制御を追加することもできます。エラーイベントを制御しない場合やトランザクションで `abort()` を呼び出した場合は、トランザクションがロールバックされて、`abort` イベントが発生します。それ以外の場合は、すべての保留中のリクエストが完了した後に `complete` イベントが発生します。多くのデータベース操作を行っている場合は、個々のリクエストではなくトランザクションを追跡すると、確実に健全性を促進します。

トランザクションを確保したら、そこからオブジェクトストアを取得しなければならないでしょう。トランザクションは、作成時に指定したオブジェクトストアだけを提供します。そして、必要なデータをすべて追加できます。

```js
// すべてのデータがデータベースに追加されたときに行う処理
transaction.oncomplete = (event) => {
  console.log("All done!");
};

transaction.onerror = (event) => {
  // エラー制御を忘れずに!
};

const objectStore = transaction.objectStore("customers");
customerData.forEach((customer) => {
  const request = objectStore.add(customer);
  request.onsuccess = (event) => {
    // event.target.result === customer.ssn;
  };
});
```

`add()` を呼び出して生成されたリクエストの `result` は、追加された値のキーです。よってこのケースでは、オブジェクトストアでキーパスとして `ssn` プロパティを使用していますので、追加されたオブジェクトの `ssn` プロパティと等しくなります。`add()` 関数では、データベース内に同一のキーを持つオブジェクトが存在しないことを要求しますので注意してください。既存の項目を変更しようとする場合や、既存の項目があるかを配慮しない場合は、データベース内の項目の更新の節で説明している `put()` 関数を使用できます。

### データベースからのデータの削除

データの削除もよく似ています。

```js
const request = db
  .transaction(["customers"], "readwrite")
  .objectStore("customers")
  .delete("444-44-4444");
request.onsuccess = (event) => {
  // 削除完了!
};
```

### データベースからのデータの取得

データベースは情報を持っていますので、いくつかの方法でデータを読み出すことができます。まずは、単純に `get()` を使用します。以下のように、値を読み出すためにキーを提供しなければなりません。

```js
const transaction = db.transaction(["customers"]);
const objectStore = transaction.objectStore("customers");
const request = objectStore.get("444-44-4444");
request.onerror = (event) => {
  // エラー処理!
};
request.onsuccess = (event) => {
  // request.result に対して行う処理!
  console.log(`Name for SSN 444-44-4444 is ${request.result.name}`);
};
```

"単純に" 読み出すにも多くのコードがあります。データベースレベルでエラー処理を行うとすれば、コードを少々短縮できることを以下に示します。

```js
db
  .transaction("customers")
  .objectStore("customers")
  .get("444-44-4444").onsuccess = (event) => {
  console.log(`Name for SSN 444-44-4444 is ${event.target.result.name}`);
};
```

どのように動作するかわかりますか? オブジェクトストアが 1 つしかありませんので、トランザクションで必要とするオブジェクトストアのリストを渡さずに、名称を文字列で渡しています。また、データベースから読み出すだけですので、`"readwrite"` トランザクションは不要です。モードを指定せずに `transaction()` を呼び出すと、`"readonly"` トランザクションになります。さらに細かいことですが、実はリクエストオブジェクトを変数に保存していません。DOM イベントはターゲットとしてリクエストを持ちますので、`result` プロパティを得るためにイベントを使用できます。

トランザクションでスコープやモードを制限することにより、データアクセスを高速化できることに留意してください。ヒントを 2 つ紹介します。

* スコープを定義するときは、必要なオブジェクトストアのみ指定します。これにより、同時にスコープが重なり合うことなく、複数のトランザクションを実行できます。
* `readwrite` トランザクションモードは、必要な場合に限り指定します。`readonly` トランザクションはスコープが重なっても複数同時に実行できますが、`readwrite` トランザクションはオブジェクトストアに対して 1 個しか実行できません。詳しくは、IndexedDB の主な特徴と基本用語の基本的な概念の記事でトランザクションの定義をご覧ください。
### データベース内の項目の更新

読み出したデータを更新して IndexedDB に書き戻す方法は、とてもシンプルです。先ほどのサンプルを多少更新しましょう。

```js
const objectStore = db
  .transaction(["customers"], "readwrite")
  .objectStore("customers");
const request = objectStore.get("444-44-4444");
request.onerror = (event) => {
  // エラー処理!
};
request.onsuccess = (event) => {
  // 更新したい、古い値を取得します。
  const data = event.target.result;

  // オブジェクト内の値を、希望する値に更新します。
  data.age = 42;

  // 更新したオブジェクトを、データベースに書き戻します。
  const requestUpdate = objectStore.put(data);
  requestUpdate.onerror = (event) => {
    // エラーが発生した場合の処理
  };
  requestUpdate.onsuccess = (event) => {
    // 成功 - データを更新しました!
  };
};
```

ここでは `objectStore` を作成して、ssn の値 (`444-44-4444`) で特定される顧客レコードの取り出しを要求しています。リクエストの結果を変数 (`data`) に代入して、そのオブジェクトの `age` プロパティを更新します。そして、顧客レコードを `objectStore` に書き戻して前の値を上書きする、第 2 のリクエスト (`requestUpdate`) を作成します。

**メモ:** このケースではデータベースから読み出すだけでなく書き込みも行いたいので、`readwrite` トランザクションを指定しました。

### カーソルの使用

`get()` を使用する際は、読み出したいキーがどれかを知っていることが必要です。オブジェクトストア内のすべての値を渡り歩きたい場合は、カーソルを使用できます。以下のようなものです。

```js
const objectStore = db.transaction("customers").objectStore("customers");

objectStore.openCursor().onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    console.log(`Name for SSN ${cursor.key} is ${cursor.value.name}`);
    cursor.continue();
  } else {
    console.log("No more entries!");
  }
};
```

`openCursor()` 関数は、引数がいくつかあります。第一に、すぐに取得するキーレンジオブジェクトを使用して、読み出すアイテムの範囲を制限できます。第二に、反復処理を行いたい方向を指定できます。上記の例では、すべてのオブジェクトを昇順方向に反復します。カーソルの成功イベントのコールバックは、やや特殊です。カーソルオブジェクト自体は、リクエストの `result` です (上記の例では略記法を使用しており、`event.target.result` になります)。そして実際のキーと値は、カーソルオブジェクトの `key` プロパティと `value` プロパティで見つかります。進み続けたい場合は、カーソルで `continue()` を呼び出さなければなりません。データの終端に達した (または、`openCursor()` リクエストに一致する項目が存在しない) 場合は成功のコールバックを受け取りますが、`result` プロパティが `undefined` になります。

カーソルをよく使用するパターンのひとつが、以下のようにオブジェクトストア内の全データを読み出して、配列に追加することです。

```js
const customers = [];

objectStore.openCursor().onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    customers.push(cursor.value);
    cursor.continue();
  } else {
    console.log(`Got all customers: ${customers}`);
  }
};
```

**メモ:** それ以外に、このような処理を行うために `getAll()` (および `getAllKeys()`)。を使用することができます。以下のコードは、前出の例とまったく同じことを行います。

```js
objectStore.getAll().onsuccess = (event) => {
  console.log(`Got all customers: ${event.target.result}`);
};
```

これはオブジェクトを横着な方法で作成するため、カーソルの `value` プロパティの検索に関してパフォーマンスコストが発生します。例えば `getAll()` を使用するとき、Gecko はすべてのオブジェクトを一度に作成しなければなりません。例えばそれぞれのキーを検索することにのみ関心がある場合は、`getAll()` よりもカーソルを使用する方がとても効率的です。オブジェクトストア内の全データの配列を得ようとしている場合は、`getAll()` を使用しましょう。

### インデックスの使用

SSN は個人を一意に識別しますので、キーとして SSN を使用して顧客データを保管することは論理的です。(プライバシーの観点でよいアイデアであるかは別の問題であり、この記事の対象外です) 一方、名前で顧客を検索しなければならない場合は、正しいものが見つかるまでデータベース内のすべての SSN に対して反復処理を行わなければなりません。この方法による検索はとても遅いため、代わりにインデックスを使用するとよいでしょう。

```js
// 最初に、 request.onupgradeneeded の中にインデックスを生成したか確認してください。
// objectStore.createIndex("name", "name");
// まだであれば、 DOMException が発生します。

const index = objectStore.index("name");

index.get("Donna").onsuccess = (event) => {
  console.log(`Donna's SSN is ${event.target.result.ssn}`);
};
```

`"name"` インデックスは一意ではないので、`name` に `"Donna"` が設定されている項目は複数存在する可能性があります。この場合は常に、キーの値がもっとも小さいものを取得します。

指定した `name` に該当するすべての項目にアクセスしなければならない場合は、カーソルを使用します。インデックス上で、2 種類のカーソルを開くことができます。ノーマルカーソルは、インデックスのプロパティと、オブジェクトストア内のオブジェクトを紐づけます。キーカーソルは、インデックスのプロパティと、オブジェクトストア内にオブジェクトを保存するために使用するキーを紐づけます。これらの違いを以下に示します。

```js
// 顧客レコードのオブジェクト全体を得るために、ノーマルカーソルを使用します。
index.openCursor().onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // cursor.key は "Bill" のような名前、cursor.value はオブジェクト全体です。
    console.log(
      `Name: ${cursor.key}, SSN: ${cursor.value.ssn}, email: ${cursor.value.email}`,
    );
    cursor.continue();
  }
};

// 顧客レコードのオブジェクトのキーを得るために、キーカーソルを使用します。
index.openKeyCursor().onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // cursor.key は "Bill" のような名前、cursor.value は SSN です。
    // 保存されたオブジェクトの他の部分を直接取得する方法はありません。
    console.log(`Name: ${cursor.key}, SSN: ${cursor.primaryKey}`);
    cursor.continue();
  }
};
```

### カーソルの範囲や方向を指定する

カーソルで参照する値の範囲を制限したい場合は、`IDBKeyRange` オブジェクトを使用して、`openCursor()` または `openKeyCursor()` の第 1 引数として渡します。ひとつのキーのみ許可するキーレンジ、下限または上限の片方を持つキーレンジ、あるいは下限と上限の両方を持つキーレンジを作成できます。境界は "closed" (すなわち、キーレンジは指定した値を含む) または "open" (すなわち、キーレンジは指定した値を含まない) のどちらにもできます。使い方を以下に示します。

```js
// "Donna" にのみ一致します。
const singleKeyRange = IDBKeyRange.only("Donna");

// "Bill" より先のすべてに一致します。"Bill" を含みます。
const lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");

// "Bill" より先のすべてに一致します。ただし "Bill" は含みません。
const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);

// "Donna" までのすべてに一致します。ただし "Donna" は含みません。
const upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);

// "Bill" から "Donna" までに一致します。ただし "Donna" は含みません。
const boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);

// いずれかのキーレンジを使用するには、openCursor()/openKeyCursor() の第 1 引数として渡します。
index.openCursor(boundKeyRange).onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // 一致した場合の処理。
    cursor.continue();
  }
};
```

昇順 (すべてのカーソルのデフォルトの方向) ではなく、降順に反復処理を行いたい場合があるかもしれません。方向の切り替えは、`openCursor()` の第 2 引数に `prev` を渡すことで実現します。

```js
objectStore.openCursor(boundKeyRange, "prev").onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // 項目に対して行う処理
    cursor.continue();
  }
};
```

方向を変えたいだけで表示する結果は制限しない場合は、第 1 引数に `null` を渡します。

```js
objectStore.openCursor(null, "prev").onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // 項目に対して行う処理
    cursor.continue();
  }
};
```

`"name"` インデックスは一意ではありませんので、`name` が同じ項目が複数存在する可能性があります。キーは常に一意でなければならないため、オブジェクトストアでこのような状況は発生できないことに注意してください。インデックスに対して反復処理を行う際に重複を取り除きたい場合は、方向の引数に `nextunique` (逆向きであれば `prevunique`) を指定します。`nextunique` または `prevunique` を使用すると、常にキーが最小の項目が返ります。

```js
index.openKeyCursor(null, "nextunique").onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    // 項目に対して行う処理
    cursor.continue();
  }
};
```

有効な方向の引数については、「IDBCursor 定数」をご覧ください。

ウェブアプリが別のタブで開かれているときにバージョンを変更する
-------------------------------

データベースのバージョン変更が必要である場合に ウェブアプリでそのようなことを行うときは、ユーザーが古いバージョンの ウェブアプリをタブで開いている場合に別のタブで新しいバージョンのアプリを読み込んだときに発生することを考慮しなければなりません。データベースの実際のバージョンより大きなバージョンを指定して `open()` を呼び出すときは、データベースに変更を施す前に、他にデータベースを開いているものが明示的に要求を認めなければなりません (それらを閉じるか再読み込みするまで、`onblocked` イベントが発生します)。使い方を以下に示します。

```js
const openReq = mozIndexedDB.open("MyTestDatabase", 2);

openReq.onblocked = (event) => {
  // 他のタブがデータベースを読み込んでいる場合は、処理を進める前に
  // それらを閉じなければなりません。
  console.log("このサイトを開いている他のタブをすべて閉じてください!");
};

openReq.onupgradeneeded = (event) => {
  // 他のデータベースはすべて閉じられました。すべての処理を行います。
  db.createObjectStore(/\* … \*/);
  useDatabase(db);
};

openReq.onsuccess = (event) => {
  const db = event.target.result;
  useDatabase(db);
  return;
};

function useDatabase(db) {
  // 別のページがバージョン変更を求めた場合に、通知されるようにするためのハンドラーを追加するようにしてください。
  // データベースを閉じなければなりません。データベースを閉じると、別のページがデータベースをアップグレードできます。
  // これを行わなければ、ユーザーがタブを閉じるまでデータベースはアップグレードされません。
  db.onversionchange = (event) => {
    db.close();
    console.log(
      "新しいバージョンのページが使用可能になりました。再読み込みしてください!",
    );
  };

  // データベースを使用する処理
}
```

すでに開かれているアプリが新たにデータベースを開こうとするコードを開始したが、古いバージョンのデータベースを使用している状況に対処するため、`VersionError` エラーもリッスンしましょう。

セキュリティ
------

IndexedDB は同一生成元の原則を使用します。すなわち、ストアとサイトの生成元 (通常、サイトのドメインまたはサブドメイン) を紐づけますので、他の生成元からアクセスすることはできません。

サードパーティの window コンテンツ (例えば `<iframe>` のコンテンツ) は、ブラウザーがサードパーティ Cookie を禁止していない限り、自身が埋め込まれている生成元の IndexedDB ストアにアクセスできます (Firefox バグ 1147821 をご覧ください)。

ブラウザーの終了に関する警告
--------------

ブラウザーを終了するとき (例えばユーザーが「終了」や「閉じる」ボタンをクリックしたとき)、データベースを含むディスクは予期せず削除されたり、データベースストアへのパーミッションが失われたり、次のことが起きたりします。

1. 影響するデータベース (あるいは、ブラウザーを終了する場合はすべての開いているデータベース) の各トランザクションは `AbortError` とともに中断されます。この効果は各トランザクションで `IDBTransaction.abort()` が呼ばれたのと同等です。
2. すべてのトランザクションが完了していたら、データベース接続は閉じられます。
3. 最後に、データベース接続を表す `IDBDatabase` オブジェクトは `close` イベントを受け取ります。 `IDBDatabase.onclose` イベントハンドラーを使ってこのイベントを待ち受けできます。その結果、データベースが予期せず閉じられたことがわかります。

上記の挙動は新しく、ブラウザーの Firefox 50、Google Chrome 31 以降 (おおよそ) のリリースで利用できます。

このバージョンのブラウザーの前は、トランザクションは暗黙裡に中断され、 `close` イベントが発行されず、予期せぬデータベースの停止を検出する方法はありませんでした。

ユーザーはいつでもブラウザーを終了することができますので、特定のトランザクションが完了することをあてにしたり、完了しなかったことを知ったりすることはできません。この動作が暗示することがいくつかあります。

第一に、データベースであらゆるトランザクションが終了したときに、常に一貫性がある状態を保つように注意するべきです。例えば、ユーザーが編集可能な項目のリストを保存する IndexedDB を使用していると想定します。オブジェクトストアを消去してから新たなリストを書き込むことにより、編集後のリストを保存します。あるトランザクションでオブジェクトストアを消去して、別のトランザクションで新たなリストを書き込むとすれば、消去した後かつ書き込む前にブラウザーが閉じられる危険性があり、その場合は空のデータベースが残ります。これを避けるために、消去と書き込みをひとつのトランザクションに結合しましょう。

第二に、データベースのトランザクションと `unload` イベントを紐づけるべきではありません。ブラウザーを閉じることで `unload` イベントが発生した場合、`unload` イベントハンドラーで作成したトランザクションは完了しません。ブラウザーのセッションにわたって情報を管理するための直感的な方法は、ブラウザー (または特定のページ) を開いたときに情報を読み込んで、ユーザーとブラウザーとの対話に応じて更新して、ブラウザー (またはページ) を閉じるときに保存する流れです。しかし、これは動作しないでしょう。データベースのトランザクションは `unload` イベントハンドラーで作成されますが、これらは非同期処理ですので、実行できるようになる前に中止されるでしょう。

実は通常のブラウザー終了であっても、IndexedDB のトランザクションが完了するよう保証する手段はありません。Firefox バグ 870645 をご覧ください。通常の終了通知の回避策として、トランザクションの状況を追跡して、アンロード時にトランザクションが完了していないことをユーザーに警告するための `beforeunload` イベントを追加するとよいでしょう。

少なくとも中止通知と `IDBDatabase.onclose` を追加することで、いつ起こったのかがわかります。

ロケールを意識した並べ替え
-------------

Mozilla は Firefox 43 以降に、IndexedDB のデータでロケールを意識した並べ替えを行う機能を実装しました。デフォルトでは、IndexedDB は文字列の並べ替えで国際化にまったく対処せず、すべてが英語のテキストであるかのように並べ替えられます。例えば b、á、z、a は以下のように並べ替えられます。

* a
* b
* z
* á

これは明らかに、ユーザーが望むデータの並べ替えではありません。例えば Aaron と Áaron は、連絡先一覧で隣り合うべきです。従って適切な国際化並べ替えを実現するには、データセット全体をメモリーに読み込んで、クライアントサイド JavaScript で並べ替えを実行しなければならず、非効率的です。

この新機能は、開発者が `IDBObjectStore.createIndex()` を使用してインデックスを作成する際にロケールを指定できるようにします (引数を確認してください)。データセットに対して反復処理を行うためにカーソルを使用するときに、ロケールを意識した並べ替えを行いたい場合は、特化した `IDBLocaleAwareKeyRange` を使用できます。

また `IDBIndex` には、ロケールが指定されているか、およびどのロケールが指定されているかを特定するために追加された新たなプロパティがあります。`locale` (指定されたロケール、または未指定であれば null を返します) と `isAutoLocale` (プラットフォームの既定のロケールを使用する自動ロケールでインデックスが作成されていれば `true`、そうでなければ `false` を返します) です。

**メモ:** 現在、この機能はフラグで隠されています。有効化して実験するには、about:config に移動して `dom.indexedDB.experimental` を有効化してください。

包括的な IndexedDB の例
-----------------

IndexedDB API を使用した完全な例があります。この例では、出版物を格納し、取得するために IndexedDB を使用しています。

* 例を試す
* ソースコードを見る
関連情報
----

必要に応じて、より多くの情報を知るための記事集です。

### リファレンス

* IndexedDB API リファレンス
* Indexed Database API Specification
* IndexedDB インターフェイスファイル (Firefox のソースコード内)
### チュートリアルとガイド

* Databinding UI Elements with IndexedDB (2012)
* IndexedDB — The Store in Your Browser
### ライブラリー

* localForage: クライアント側のデータストレージ向けに、シンプルな name:value 形式の構文を提供するポリフィルです。バックグラウンドで IndexedDB を使用しますが、IndexedDB をに対応していないブラウザーでは Web SQL （非推奨）や localStorage にフォールバックします。
* Dexie.js: 優良でシンプルな構文により高速なコード開発を可能にする、IndexedDB のラッパーです。
* JsStore: SQL 風の構文による IndexedDB のラッパーです。
* MiniMongo: クライアント側のインメモリーの mongodb で localstorage と server sync over http を元にしたもの。MiniMongo は MeteorJS で使われています。
* PouchDB: クライアント側のブラウザー内の CouchDB 実装で IndexedDB を使っています。
* IDB: IndexedDB API をほぼ反映した小さなライブラリーですが、使いやすさを大きく変える小さな改良が加えられています。
* idb-keyval: IndexedDB で実装された超シンプルで小さな (~600B) プロミスベースのキーバリューストア
* $mol\_db: 小さな (~1.3kB) TypeScript のファサードで、プロミスベースの API と自動マイグレーションを備えています。
* RxDB IndexedDB の上に使用することができる NoSQL クライアントサイドデータベースです。インデックス、圧縮、レプリケーションに対応して います。また、 IndexedDB にクロスタブ機能やオブザーバー機能を追加しています。


IndexedDB の主な特徴と基本用語 - Web API

IndexedDB の主な特徴と基本用語
====================

この記事では IndexedDB の主な特徴を説明し、IndexedDB API の理解に関連する重要な用語を紹介しています。

また、以下の記事も参考になるでしょう。

* API の使用方法に関する詳細なチュートリアルについては、IndexedDB の使用を参照してください。
* IndexedDB API のリファレンス文書については、IndexedDB API のメイン記事と、IndexedDB で使用されるオブジェクトの型を記したそのサブページを参照してください。
* ブラウザーがバックグラウンドでデータを保存する方法の詳細については、ブラウザーのストレージ制限と削除基準を参照してください。
主な特徴
----

IndexedDB は、ユーザーのブラウザー内にデータを永続的に保存するための方法です。ネットワークの利用可否にかかわらず、豊富なクエリー機能を備えたウェブアプリケーションを作成できるため、オンラインでもオフラインでも動作します。IndexedDB は、大量のデータを保存するアプリケーション (貸し出し用図書館の DVD カタログなど) や、インターネットへの持続的な接続を必要としないアプリケーション (メールクライアント、ToDo リスト、メモ帳など) に有効です。

IndexedDB では、「キー」に基づいてインデックス化されたオブジェクトを保存・取得することができます。データベースへの変更は、すべてトランザクション内で行われます。多くのウェブストレージ技術と同様に、IndexedDB は同一オリジンポリシーに従っています。そのため、ドメイン内の保存データにはアクセスできますが、異なるドメイン間のデータにはアクセスできません。

他の種類のデータベースでの作業を前提としていると、IndexedDB での作業に戸惑うことがあるかもしれません。そのため、以下のような IndexedDB の主な特徴を覚えておくことが重要です。

* **IndexedDB データベースは、キーと値の組を格納します。** 値は複雑な構造のオブジェクトで、キーはそのオブジェクトのプロパティです。オブジェクトの任意のプロパティを使用するインデックスを作成して、迅速な検索や並べ替えされた列挙を行うことができます。キーにはバイナリーオブジェクトを使用することができます。
* **IndexedDB は、トランザクションデータベースモデルに基づいて構築されています。** IndexedDB で行うことは、常にトランザクションのコンテキストで行われます。IndexedDB API には、インデックス、テーブル、カーソルなどを表す多くのオブジェクトが用意されていますが、これらはそれぞれ特定のトランザクションに関連付けられています。そのため、トランザクションの外でコマンドを実行したり、カーソルを開いたりすることはできません。トランザクションには十分に定義された有効期間があるため、トランザクションが完了した後に使用しようとすると、例外が発生します。また、トランザクションは自動コミットされ、手動でコミットすることはできません。
 このトランザクションモデルは、ユーザーがウェブアプリケーションの 2 つのインスタンスを 2 つの異なるタブで同時に開いた場合のことを考えると、とても有用です。トランザクション操作がなければ、 2 つのインスタンスが互いの変更に干渉してしまう可能性があります。データベースのトランザクションに慣れていない方は、Wikipedia のトランザクションに関する記事をご覧ください。また、「定義」の章のトランザクションもご覧ください。
* **IndexedDB API は、ほとんどが非同期です。** API は値を返すことでデータを提供するわけではありません。コールバック関数を渡す必要があります。同期的な方法でデータベースに値を「格納」したり、データベースから値を「取り出す」ことはしません。代わりに、データベース操作を「リクエスト」します。操作が終了すると DOM イベントで通知され、そのイベントの種類によって操作が成功したか失敗したかが分かります。最初は少し複雑に聞こえるかもしれませんが、そこには健全性を保つための対策が組み込まれています。これは、XMLHttpRequest が動作する方法と大きな違いはありません。
* **IndexedDB は多くのリクエストを使用します。** リクエストは、前述の成功または失敗の DOM イベントを受け取るオブジェクトです。このオブジェクトには `onsuccess` と `onerror` のプロパティがあり、`addEventListener()` と `removeEventListener()` を呼び出すことができます。また、`readyState`、`result`、`errorCode` の各プロパティがあり、リクエストの状態を知ることができます。`result` プロパティは、リクエストの生成方法 (例えば `IDBCursor` インスタンスや、データベースに挿入したばかりの値のキー) に応じて、さまざまなものになるため、特に魔法のようなものです。
* **IndexedDB は DOM イベントを使って、結果が利用可能になったことを通知します。** DOM イベントには、必ず `type` プロパティがあります (IndexedDB では、最も一般的に `"success"` または `"error"` に設定されます)。また、DOM イベントには、イベントの目的地を示す `target` プロパティがあります。ほとんどの場合、イベントの `target` は、何らかのデータベース操作の結果として生成された `IDBRequest` オブジェクトです。成功イベントはバブルアップしませんし、キャンセルもできません。一方、エラーイベントはバブリングします、キャンセルも可能です。これは非常に重要なことで、エラーイベントはキャンセルされない限り、実行中のトランザクションを中断します。
* **IndexedDB はオブジェクト指向です。** IndexedDB は、行と列の集合体であるテーブルを持つリレーショナルデータベースではありません。この重要かつ根本的な違いは、アプリケーションの設計・構築方法に影響します。
 従来のリレーショナルデータストアでは、データの行と名前の付いたデータの列の集合体を格納するテーブルがあります。一方、IndexedDB では、データの種類に応じてオブジェクトストアを作成し、そのストアに JavaScript オブジェクトを永続化する必要があります。各オブジェクトストアには、クエリや反復処理を効率的に行うためのインデックスのコレクションを持つことができます。オブジェクト指向データベース管理システムに慣れていない方は、Wikipedia のオブジェクトデータベースの記事をお読みください。
* **IndexedDB は Structured Query Language (SQL) を使用しません。** インデックスに対するクエリーを使用してカーソルを生成し、そのカーソルを使用して結果セットを反復処理します。NoSQL システムについてよく知らない方は、Wikipedia の NoSQL に関する記事をご覧ください。
* **IndexedDB は、同一オリジンポリシーを採用しています**。オリジンとは、スクリプトを実行している文書の URL のドメイン、アプリケーション層のプロトコル、およびポートのことです。各オリジンには、それぞれ関連するデータベースのセットがあります。すべてのデータベースには、オリジン内で識別するための名前があります。
 IndexedDB にはセキュリティ境界が課せられており、アプリケーションが異なるオリジンのデータにアクセスすることを防ぎます。例えば、`http://www.example.com/app/` のアプリやページは、`http://www.example.com/dir/` からはオリジンが同じであるためデータを取得することができますが、`http://www.example.com:8080/dir/` (ポートが異なる) や `https://www.example.com/dir/` (プロトコルが異なる) からは、オリジンが異なるためデータを取得することはできません。

**メモ:** サードパーティのウィンドウコンテンツ (例: `<iframe>` コンテンツ) は、ブラウザーがサードパーティのクッキーを受け入れないように設定されていない限り、埋め込まれたオリジンの IndexedDB ストアにアクセスすることができます (Firefox バグ 1147821 を参照)。
### 制限事項

IndexedDB は、クライアントサイドのストレージを必要とするほとんどのケースをカバーするように設計されています。しかし、以下のようないくつかのケースには対応していません。

* 国際化に対応した並べ替え。すべての言語で文字列が同じように並べ替えされるわけではないので、国際化に対応した並べ替えには対応していません。データベースは特定の国際化に対応した順序でデータを保存することはできませんが、データベースから読み取ったデータを自分で並べ替えすることはできます。ただし、Firefox 43 以降、実験的なフラグを有効にすることで、ロケールを考慮した並べ替えが可能になっています (現在は Firefox のみ)。
* 同期。この API は、サーバー側のデータベースとの同期を行うようには設計されていません。クライアント側の indexedDB データベースとサーバー側のデータベースを同期させるコードを書く必要があります。
* 全文検索。この API には、 SQL の `LIKE` 演算子に相当するものがありません。

また、以下のような条件でブラウザーがデータベースを消去することがあるので注意が必要です。

* ユーザーが消去を要求した場合。多くのブラウザーには、Cookie、ブックマーク、保存されたパスワード、IndexedDB データなど、特定のウェブサイトに保存されたすべてのデータを消去できる設定があります。
* ブラウザーがプライベートブラウジングモードになっている場合。一部のブラウザーには、「プライベートブラウジング」 (Firefox) または「シークレット」 (Chrome) モードがあります。セッションの終了時に、ブラウザーはデータベースを消去します。
* ディスクまたはクォータの容量の上限に達した場合。
* データが破損した場合。
* この機能に対して互換性のない変更が行われた場合。

正確な状況やブラウザーの機能は時間とともに変化しますが、ブラウザーベンダーの一般的な考え方は、可能な限りデータを残すために最善の努力をするというものです。

主な用語
----

この節では、IndexedDB API の理解に関連する主な用語を定義および説明します。

### データベース

#### データベース

普通 1 つ以上の*オブジェクトストア*で構成される、情報の格納庫です。それぞれのデータベースには以下のものがあります。

* 名前。これは、特定のオリジン内でデータベースを識別し、その生涯を通じて一定です。名前は任意の文字列値 (空文字列を含む) とすることができます。
* 現在の*バージョン*。データベースが最初に作成されたとき、特に指定がなければそのバージョンは整数の 1 です。各データベースは、常に 1 つのバージョンしか持つことができません。

#### データベースコネクション

データベースを開くために作成される操作。指定されたデータベースは、同時に複数の接続を保有することができます。

#### 永続性

Firefox では、IndexedDB は以前は**永続性**がありました。つまり、読み書きトランザクションにおいて、すべてのデータがディスクにフラッシュされたことが保証されたときにのみ、`complete` が発行されていました。

Firefox 40 では、IndexedDB トランザクションは、パフォーマンスを向上させるために、他の IndexedDB に対応するブラウザーと同様に永続性の保証を緩和しています (Firefox バグ 1112702 を参照)。この場合、 `complete` イベントは、OS がデータの書き込みを指示した後に発生しますが、そのデータが実際にディスクにフラッシュされる前に発生する可能性もあります。そのため、イベントは以前よりも早く配信されるかもしれませんが、データがディスクにフラッシュされる前に OS がクラッシュしたり、システムの電源が切れたりすると、トランザクション全体が失われてしまう可能性がわずかながらあります。このような致命的な事象は稀であるため、ほとんどの人はこれ以上気にする必要はありません。

**メモ:** Firefox では、何らかの理由で永続性を確保したい場合 (たとえば、後で再計算できない重要なデータを保存している場合)、実験的な (標準外の) `readwriteflush` モードを使用してトランザクションを作成することで、`complete` イベントを配信する前にトランザクションをディスクに強制的にフラッシュさせることができます(`IDBDatabase.transaction` を参照)。これは現在実験的なものであり、`about:config` で `dom.indexedDB.experimental` 設定項目が `true` に設定されている場合にのみ使用できます。

#### インデックス

インデックスは、参照オブジェクトストアと呼ばれる別のオブジェクトストアにあるレコードを探すために特化したオブジェクトストアです。インデックスは永続的なキー-値ストレージで、そのレコードの値の部分が参照するオブジェクトストアのレコードのキー部分となります。インデックス内のレコードは、参照されるオブジェクトストア内のレコードが挿入、更新、または削除されるたびに、自動的に入力されます。インデックス内の各レコードは、参照するオブジェクトストア内の1つのレコードのみを参照することができますが、複数のインデックスが同じオブジェクトストアを参照することは可能です。オブジェクトストアが変更されると、そのオブジェクトストアを参照しているすべてのインデックスが自動的に更新されます。

また、キーを使用してオブジェクトストア内のレコードを見いだすこともできます。

インデックスの使用について詳しくは、 IndexedDB の使用を参照してください。インデックスについてのリファレンス記事は、 IDBKeyRange を参照してください。

#### オブジェクトストア

データベースにデータを保存する仕組みです。オブジェクトストアはレコードを持続的に保持しており、これはキーと値の組です。オブジェクトストア内のレコードは、*キー* によって昇順に整列して保存されています。

すべてのオブジェクトストアには、そのデータベース内で一意となる名前が必要です。オブジェクトストアは、オプションで *キージェネレーター* と *キーパス* を持つことができます。オブジェクトストアにキーパスがある場合は *インラインキー*、ない場合は *アウトオブラインキー* が使用されます。

オブジェクトストアのリファレンス文書は、 `IDBObjectStore` を参照してください。

#### リクエスト

データベースへの読み書きが行われる処理。すべてのリクエストは、 1 つの読み取りまたは書き込み処理を表します。

#### トランザクション

特定のデータベースで行う、原子性を持つデータアクセスやデータ変更の操作のセットです。これは、データベース内のデータと対話する手段です。実際は、データベース内のデータの読み取りや変更はトランザクション内で実施しなければなりません。

書き込みトランザクションの*スコープ*が重ならない限り、ひとつのデータベース接続で同時に複数のアクティブなトランザクションが存在できます。トランザクションのスコープは生成時に定義され、トランザクションがどのオブジェクトストアと対話できるかや、トランザクションの持続期間にわたって保持し続けるかを示します。よって例えば、データベース接続で `flyingMonkey` オブジェクトストアのみ対象とするスコープを持つ書き込みトランザクションがすでに存在するとき、`unicornCentaur` オブジェクトストアや `unicornPegasus` オブジェクトストアをスコープで持つ別のトランザクションを開始できます。読み取りトランザクションは、スコープが重なっていても複数実行できます。

トランザクションは持続期間が短いものを除き、長時間のトランザクションがストレージ資源をロックする状況から解放するために、ブラウザーが終了させることができます。トランザクションは中止させることができ、トランザクションによるデータベースの変更箇所はロールバックされます。また、開始するトランザクションや中止するトランザクションを待つ必要はありません。

トランザクションには `readwrite`、`readonly`、`versionchange` の 3 つのモードがあります。オブジェクトストアやインデックスの生成および削除は、`versionchange` トランザクションを使用する場合に限り実行できます。トランザクションのタイプについて詳しくは、IndexedDB のリファレンスをご覧ください。

すべての操作はトランザクション内で発生しますので、トランザクションは IndexedDB の重要な概念です。トランザクションについて、特にバージョン付けとの関係については、`IDBTransaction` および関連文書をご覧ください。ここにリファレンス文書もあります。

#### バージョン

始めにデータベースを生成したとき、バージョンは整数の 1 になります。それぞれのデータベースは、一度に 1 つのバージョンを持ちます。一度に複数のバージョンを持つことはできません。バージョンを変更する唯一の方法は、現在のバージョンより大きなバージョンでデータベースを開くことです。

### キーと値

#### インラインキー

保存される値の一部として保存されるキーです。これは **キーパス** を使用して見つけます。インラインキーは、ジェネレーターを使用して生成できます。キーが生成されると、キーパスを使用してキーを値の中に保存したり、キーとして使用したりすることができます。

#### キー

オブジェクトストアに保存された値は、このデータ値によって編成および取り出しされます。オブジェクトストアは **キージェネレーター**、*キーパス*、明示的に指定した値の、3 種類の生成源のいずれかからキーを得られます。キーは、自身の前にあるものより大きな数値を持つデータ型であることが必要です。オブジェクトストア内の各レコードはオブジェクトストア内で一意のキーを持たなければならず、オブジェクトストア内で複数のレコードが同じキーを持つことはできません。

キーは 文字列、date、浮動小数点数値、配列のいずれかの型を使用できます。配列では、キーは空の値から無限大までの範囲を使用できます。また、配列の中に配列を含めることができます。文字列または整数値のキーしか使用できないという条件はありません。

代わりに、インデックスを使用してオブジェクトストア内のレコードを検索することもできます。

#### キージェネレーター

指定した順序で新たなキーを生成する仕組みです。オブジェクトストアがキージェネレーターを持たない場合は、保存するレコードのキーをアプリケーションが提供しなければなりません。ジェネレーターはストア間で共有しません。これはむしろブラウザーの実装の細部であり、Web 開発において実際にはキージェネレーターの生成やアクセスは行いません。

#### キーパス

オブジェクトストアやインデックスのどこからブラウザーがキーを取り出すべきかを定義します。有効なキーパスは空文字列、JavaScript の識別子、ピリオドで区切られた複数の JavaScript の識別子、あるいはそれらを収めた配列のいずれかを含むことができます。空白を含むことはできません。

#### アウトオブラインキー

保存する値とは別に保存されるキーです。

#### 値

それぞれのレコードは値を持っており、論理値、数値、文字列、date、オブジェクト、配列、正規表現、undefined、null を含む、JavaScript で表現可能なものをどれでも含むことができます。

オブジェクトまたは配列を保存する場合は、それらのプロパティや値もまた、有効な値をどれでも持つことができます。

また、Blob やファイルも保存可能です。仕様書 をご覧ください。

### レンジとスコープ

#### カーソル

*キーレンジ*に属する複数のレコードにわたって反復処理を行うための仕組みです。カーソルは、反復処理を行うインデックスやオブジェクトストアがどれかを示す source を持ちます。またレンジ内の位置や、レコードキーの順序について増加方向に移動しているか減少方向に移動しているかの情報も持ちます。カーソルのリファレンス文書として、`IDBCursor` をご覧ください。

#### キーレンジ

キーとして使用する、何らかのデータ型の連続的な区間です。キーまたはキーレンジを使用して、オブジェクトストアやインデックスからレコードを取り出すことができます。下限または上限を使用して、レンジを制限またはフィルターリングできます。例えばキーが x から y の間であるすべての値に対して、反復処理を行うことができます。

キーレンジのリファレンス文書として、`IDBKeyRange` をご覧ください。

#### スコープ

トランザクションの適用先であるオブジェクトストアやインデックスのセットです。読み取りのみのトランザクションのスコープは、同時に重ね合ったり実行することができます。一方、書き込みトランザクションのスコープは重ね合うことができません。同時に同一のスコープで複数のトランザクションを開始することはできますが、それらはキューに収められ、順番に実行されます。

次のステップ
------

IndexedDB の主な特徴と主要な用語を理解できたら、より具体的な作業に入ることができます。API の使い方のチュートリアルについては、IndexedDB の使用をご覧ください。

関連情報
----

* Indexed Database API 仕様書
* IndexedDB API リファレンス
* IndexedDB の使用
* IndexedDB — The Store in Your Browser


期限の確認 - Web API

期限の確認
=====

この記事では、 IndexedDB で保存された期限と現在の日時を照合する複雑な例を見てみましょう。ここでの主な課題は、保存されている期限情報 (月、時、日など) を、Date オブジェクトから取得した現在の日時と照合することです。

![サンプルアプリのスクリーンショット。赤いメインタイトルの「To do app」、テスト用の To Do 項目、ユーザーが新しいタスクを入力するための赤いフォーム。](/ja/docs/Web/API/IndexedDB_API/Checking_when_a_deadline_is_due/to-do-app.png)

この記事で紹介するアプリケーションの例は、 **To-do リスト通知**です。これは、タスクのタイトルと期限を IndexedDB に格納し、期限になったときに Notification および Vibration API を使ってユーザーに通知を行う、シンプルな To-do リストアプリケーションです。 To-do リスト通知アプリは GitHub ダウンロードしてソースコードをいじったり、アプリの動作をライブで閲覧したりすることができます。

基本的な問題点
-------

この ToDo アプリでは、まず時間と日付の情報を、機械が読め、表示されたときに人間が理解できる形式で記録し、次にそれぞれの時間と日付が現在の時点で発生しているかどうかをチェックしたいと考えました。基本的には、現在の時刻と日付を確認し、保存されている各イベントの締め切りが現在の時刻と日付に一致するかどうかを確認します。もし一致していれば、ユーザーに何らかの通知をしたいと考えています。

2 つの `Date` オブジェクトを比較するだけなら簡単ですが、もちろん人間は JavaScript が理解できるような形式で期限を入力したいわけではありません。人間が読むことのできる日付はかなり違っていて、いくつもの異なる表現があります。

### 日付情報の記録

モバイル端末での合理的な使い勝手を提供するために、そして曖昧さを減らすために、 HTML フォームを作成することにしました。

![この ToDo アプリのフォームで、タスクのタイトルを入力するフィールドと、期限の年、月、日、時、分の値が入っています。](/ja/docs/Web/API/IndexedDB_API/Checking_when_a_deadline_is_due/to-do-app-form2.png)

* ToDo リストのタイトルを入力するためのテキスト入力です。これはユーザーの入力作業の中で最も避けられないものです。
* 期限の「時」と「分」を入力するための数値入力。 `type="number"` に対応しているブラウザーでは、小さな上下矢印の数字ピッカーが表示されます。モバイルプラットフォームでは、データを入力するためのテンキーが用意されていることが多く、これは便利です。他のプラットフォームでは、標準的なテキスト入力になりますが、これは問題ありません。
* 期限の日、月、年を入力するための `<select>` 要素。これらの値は、ユーザーにとって最も曖昧な入力となるため (7, sunday, sun? 04, 4, April, Apr? 2013, '13, 13?) 日は数値で、月は月名で、年は 4 桁の年号で記録されます。

フォームの送信ボタンが押されると、 `addData()` 関数が実行され、次のように始まります。

```js
function addData(e) {
  e.preventDefault();

  if (!title.value || !hours.value || !minutes.value || !day.value || !month.value || !year.value) {
    note.innerHTML += '<li>Data not submitted — form incomplete.</li>';
    return;
  }
```

この部分では、フォームのフィールドにすべての情報が入力されているかどうかを確認します。記入されていない場合は、開発者通知ペイン (アプリの UI の左下を参照) にメッセージを表示して、何が起こっているのかをユーザーに伝え、機能を終了します。このステップは、主に HTML フォームの検証に対応していないブラウザーのためのものです (検証に対応しているブラウザーでは、 HTML で required 属性を使用して検証を強制しています)。

```js
   else {
    const newItem = [
      {
        taskTitle: title.value,
        hours    : hours.value,
        minutes  : minutes.value,
        day      : day.value,
        month    : month.value,
        year     : year.value,
        notified : "no"
      }
    ];

    // open a read/write db transaction, ready for adding the data
    const transaction = db.transaction(["toDoList"], "readwrite");

    // report on the success of opening the transaction
    transaction.oncomplete = (event) => {
      note.innerHTML += '<li>Transaction opened for task addition.</li>';
    };

    transaction.onerror = (event) => {
      note.innerHTML += '<li>Transaction not opened due to error. Duplicate items not allowed.</li>';
    };

    // create an object store on the transaction
    const objectStore = transaction.objectStore("toDoList");

    // add our newItem object to the object store
    const request = objectStore.add(newItem[0]);
```

この部分では、データベースへの挿入に必要な形式でデータを保存する `newItem` というオブジェクトを作成します。次の数行では、データベーストランザクションを開き、これが成功したか失敗したかをユーザーに通知するメッセージを提供しています。そして、新しい項目が追加される `objectStore` が生成されます。データオブジェクトの `notified` プロパティは、 To-do リストの項目の期限がまだ来ておらず、通知されていないことを示しています。これについては後ほど説明します。

**メモ:** 変数 `db` には IndexedDB のデータベースインスタンスへの参照が格納されています。この変数の様々なプロパティを使用してデータを操作することができます。

```js
    request.onsuccess = (event) => {

      note.innerHTML += '<li>New item added to database.</li>';

      title.value = '';
      hours.value = null;
      minutes.value = null;
      day.value = '01';
      month.value = 'January';
      year.value = 2020;
    };
  }
```

次の部分では、新しい項目の追加が成功したことを示すログメッセージを作成し、次のタスクが入力できるようにフォームをリセットします。

```js
  // update the display of data to show the newly added item, by running displayData() again.
  displayData();
};
```

最後に `displayData()` 関数を実行して、アプリ内のデータの表示を更新し、先ほど入力された新しいタスクを表示します。

### 期限に達したかどうかの確認

この時点でデータはデータベースに入っていますが、今度は期限に達しているかどうかをチェックしたいと思います。これを行うのが `checkDeadlines()` 関数です。

```js
function checkDeadlines() {
  const now = new Date();
```

まず、空の `Date` オブジェクトを作成して、現在の日付と時刻を取得します。簡単でしょう？ここからは少し複雑な話になります。

```js
const minuteCheck = now.getMinutes();
const hourCheck = now.getHours();
const dayCheck = now.getDate();
const monthCheck = now.getMonth();
const yearCheck = now.getFullYear();
```

`Date` オブジェクトには、内部の日付や時刻のさまざまな部分を抽出するためのメソッドがいくつかあります。ここでは、現在の分 (簡単な数値として取得)、時 (簡単な数値として取得)、日 (これは `getDate()` が必要、 `getDay()` は曜日を 1-7 で返すため)、月 (0-11 の数値を返す。下記参照)、年 (`getFullYear()` が必要、`getYear()` は非推奨であり、誰にとってもあまり役に立たない奇妙な値を返します) を読み取ります。

```js
  const objectStore = db.transaction(['toDoList'], "readwrite").objectStore('toDoList');

  objectStore.openCursor().onsuccess = (event) => {
    const cursor = event.target.result;
    let monthNumber;

    if (cursor) {
```

次にもう一つ、 IndexedDB の `objectStore` を生成し、 `openCursor()` メソッドを使用してカーソルを開きます。これは基本的に IndexedDB がストア内のすべての項目を反復処理する方法です。そして、カーソル内に有効な項目が残っている限り、カーソル内のすべての項目をループします。

```js
switch (cursor.value.month) {
  case "January":
    monthNumber = 0;
    break;
  case "February":
    monthNumber = 1;
    break;

  // other lines removed from listing for brevity

  case "December":
    monthNumber = 11;
    break;
  default:
    alert("Incorrect month entered in database.");
}
```

まず最初に行うことは、データベースに保存されている月名を、 JavaScript が理解できる月の数値に変換することです。前に見たように、 JavaScript の Date オブジェクトは月の値を 0 から 11 までの数値として生成します。

```js
if (
  Number(cursor.value.hours) === hourCheck &&
  Number(cursor.value.minutes) === minuteCheck &&
  Number(cursor.value.day) === dayCheck &&
  monthNumber === monthCheck &&
  cursor.value.year === yearCheck &&
  notified === "no"
) {
  // If the numbers all do match, run the createNotification()
  // function to create a system notification
  createNotification(cursor.value.taskTitle);
}
```

IndexedDB に格納された値と照合したい現在の時刻と日付の部分がすべて組み立てられたので、いよいよチェックを実行します。ユーザーに期限切れを知らせる何らかの通知を行う前に、すべての値が一致している必要があります。

ここでの `+` 演算子は、先頭にゼロが付いている数字を、先頭にゼロが付いていない同等の数字に変換します (例えば 09 -> 9)。これが必要なのは、 JavaScript の Date の数値には先頭にゼロがないが、データにはあるかもしれないからです。

`notified === "no"` のチェックは、 1 つの To-Do アイテムに対して 1 つの通知しか受け取れないようにするためのものです。各項目のオブジェクトに対して通知が発生すると、その `notification` プロパティが `"yes"` に設定されるので、次の繰り返しではこのチェックが通らないようにするために、 `createNotification()` 関数の中に次のようなコードを入れています (詳しくは IndexedDB の使用を読んでください)。

```js
    // now we need to update the value of notified to "yes" in this particular data object, so the
    // notification won't be set off on it again

    // first open up a transaction as usual
    const objectStore = db.transaction(['toDoList'], "readwrite").objectStore('toDoList');

    // get the to-do list object that has this title as it's title
    const request = objectStore.get(title);

    request.onsuccess = () => {
      // grab the data object returned as the result
      const data = request.result;

      // update the notified value in the object to "yes"
      data.notified = "yes";

      // create another request that inserts the item back into the database
      const requestUpdate = objectStore.put(data);

      // when this new request succeeds, run the displayData() function again to update the display
      requestUpdate.onsuccess = () => {
        displayData();
      }
```

すべてのチェックが一致した場合は、 `createNotification()` 関数を実行して、ユーザーに通知を行います。

```js
      cursor.continue();
    }
  }
}
```

この関数の最後の行では、カーソルが上に移動し、 IndexedDB に格納されている次のタスクに対して、上記の期限チェックの仕組みが実行されます。

### チェックし続ける

もちろん、上記の期限チェック機能を一度実行するだけでは意味がありません。すべての締切に達していないかどうかを常にチェックし続けたいのです。そのために、 `setInterval()` を使って 1 秒に 1 回 `checkDeadlines()` を実行します。

```js
setInterval(checkDeadlines, 1000);
```


BluetoothDevice: id プロパティ - Web API

BluetoothDevice: id プロパティ
=========================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

読み取り専用プロパティ **`BluetoothDevice.id`** は、デバイスを一意に識別する文字列を返します。

値
-

文字列です。

仕様書
---

| Specification |
| --- |
| Web Bluetooth # dom-bluetoothdevice-id |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


BluetoothDevice: name プロパティ - Web API

BluetoothDevice: name プロパティ
===========================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

読み取り専用プロパティ **`BluetoothDevice.name`** は、デバイスの人間にわかりやすい名前を表す文字列を返します。

値
-

文字列です。

仕様書
---

| Specification |
| --- |
| Web Bluetooth # dom-bluetoothdevice-name |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


BluetoothDevice: gatt プロパティ - Web API

BluetoothDevice: gatt プロパティ
===========================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

読み取り専用プロパティ **`BluetoothDevice.gatt`** は、デバイスの `BluetoothRemoteGATTServer` への参照を返します。

値
-

デバイスの `BluetoothRemoteGATTServer` への参照です。

仕様書
---

| Specification |
| --- |
| Web Bluetooth # dom-bluetoothdevice-gatt |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


EventTarget: addEventListener() メソッド - Web API

EventTarget: addEventListener() メソッド
====================================

**`addEventListener()`** は `EventTarget` インターフェイスのメソッドで、ターゲットに特定のイベントが配信されるたびに呼び出される関数を設定します。

対象としてよくあるものは `Element`、`Document`、`Window` ですが、イベントに対応したあらゆるオブジェクトが対象になることができます （`XMLHttpRequest` など）。

**メモ:** `addEventListener()` メソッドは、イベントリスナーを登録するための*推奨される*方法です。以下のような長所があります。

* 1 つのイベントに対して複数のハンドラーを追加することができます。これは、ライブラリーや JavaScript モジュール、あるいは他のライブラリーや拡張機能とうまく動作させる必要があるその他の種類のコードで特に有効です。
* `onXYZ` プロパティを使用するのとは対照的に、リスナーが起動されるときのフェーズ（キャプチャとバブリング）をより細かく制御できます。
* HTML や SVG の要素だけでなく、あらゆるイベントターゲットで動作します。

`addEventListener()` は関数または `EventListener` を実装したオブジェクトを、呼び出される `EventTarget` における指定されたイベント種別のイベントリスナーのリストに加えることで動作します。その関数やオブジェクトが既にターゲットのイベントリスナーのリストにあった場合は、その関数やオブジェクトが二重に追加されることはありません。

**メモ:** ある無名関数が特定のターゲットでイベントリスナーのリストに登録されており、後のコードで同じ無名関数が `addEventListener` の呼び出しに指定された場合、2 つ目の関数*も*そのターゲットのイベントリスナーのリストに追加されます。

実際、無名関数は、*同じ*変更のないソースコードで定義されて繰り返し呼び出されても、**繰り返しの中でも**同一にはなりません。

このような場合、同じ無名関数を繰り返し定義することは問題になることがあります。（後述のメモリーの問題を参照してください）。

 イベントリスナーが他のリスナーの内部、つまりイベントの処理中に `EventTarget` に追加された場合、そのイベントが新しいリスナーを起動することはありません。
 しかし、新しいリスナーは、バブリング中など、イベントフローの後の段階で呼び出されることがあります。

構文
--

```js
addEventListener(type, listener)
addEventListener(type, listener, options)
addEventListener(type, listener, useCapture)
```

### 引数

`type`

対象とするイベントの種類を表す文字列です。

`listener`

指定された種類のイベントが発生するときに通知（`Event` インターフェースを実装しているオブジェクト）を受け取るオブジェクト。これは `null` であるか、`handleEvent()` メソッドのあるオブジェクトか、JavaScript の関数の何れかでなければなりません。コールバックについて詳しくは、イベントリスナーのコールバックを参照してください。

`options` 省略可

対象のイベントリスナーの特性を指定する、オプションのオブジェクトです。次のオプションが使用できます。

`capture` 省略可

論理値で、この型のイベントが DOM ツリーで下に位置する `EventTarget` に配信 (dispatch) される前に、登録された `listener` に配信されることを示します。指定されていない場合は、既定で `false` になります。

`once` 省略可

論理値で、 `listener` の呼び出しを一回のみのとしたいかどうかを値で指定します。 `true` を指定すると、 `listener` は一度実行された時に自動的に削除されます。指定されていない場合は、既定で `false` になります。

`passive` 省略可

論理値で、 `true` ならば、 `listener` で指定された関数が `preventDefault()` を呼び出さないことを示します。呼び出されたリスナーが `preventDefault()` を呼び出すと、ユーザーエージェントは何もせず、コンソールに警告を出力します。指定されていない場合、既定で `false` になります。ただし、Safari 以外のブラウザーでは、`wheel`、`mousewheel`、`touchstart`、`touchmove` の各イベントでは `true` になります。詳細はパッシブリスナーによるスクロールの性能改善をご覧ください。

`signal` 省略可

`AbortSignal` です。指定された `AbortSignal` オブジェクトの `abort()` メソッドが呼び出された時に、リスナーが削除されます。指定されていない場合は、`AbortSignal` がリスナーに関連付けられません。

`useCapture` 省略可

 論理値で、この型のイベントが、DOM ツリー内の下の `EventTarget` に配信される*前*に、登録された `listener` に配信されるかどうかを示します。ツリーを上方向にバブリングしているイベントは、キャプチャを使用するように指定されたリスナーを起動しません。イベントのバブリングとキャプチャは、両方の要素がそのイベントのハンドラーを登録している場合に、別の要素内に入れ子になっている要素で発生するイベントを伝播する 2 つの方法です。イベント伝播モードは、要素がイベントを受け取る順番を決定します。詳細な説明は DOM Level 3 Events と JavaScript Event order を参照してください。
 指定されていない場合、 `useCapture` は既定で `false` となります。

**メモ:** イベントターゲットに登録されたイベントリスナーは、キャプチャフェーズやバブリングフェーズではなく、ターゲットフェーズのイベントになります。
 キャプチャリングフェーズのイベントリスナーは、キャプチャリングフェーズ以外のイベントリスナーよりも先に呼び出されます。

`wantsUntrusted` 省略可
Non-standard

`true` の場合、このリスナーはウェブコンテンツによって発行された合成イベント (カスタムイベント) を受け取ります (ブラウザーのクロームでは既定で `false` ですが、一般のウェブページでは `true` です)。この引数は、主にアドオンやブラウザー自身の役に立つものです。

### 返値

なし (`undefined`)。

使用上の注意
------

### イベントリスナーのコールバック

イベントリスナーには、コールバック関数または `handleEvent()` メソッドを持つオブジェクトの何れかをコールバック関数として指定することができます。

コールバック関数自体は、 `handleEvent()` メソッドと同じ引数と返値を持ちます。つまり、コールバック関数は発生したイベントを説明する `Event` に基づくオブジェクトを唯一の引数として受け付け、何も返しません。

たとえば、次のイベントハンドラーコールバックは、 `fullscreenchange` および `fullscreenerror` の両方を処理するために使用することができます。

```js
function eventHandler(event) {
  if (event.type === "fullscreenchange") {
    /\* handle a full screen toggle \*/
  } else {
    /\* handle a full screen toggle error \*/
  }
}
```

### オプションの対応の安全な検出

DOM 仕様書の古い版では、 `addEventListener()` の第 3 引数はキャプチャーを使用するかどうかを示す論理値でした。時間の経過とともに、より多くのオプションが必要であることが明らかになりました。関数にさらに多くの引数を追加する (オプションの値を扱うときに非常に複雑になります) のではなく、第 3 引数は、イベントリスナーを削除する過程を設定するためのオプションの値を定義するさまざまなプロパティを含むことができるオブジェクトに変更されました。

古いブラウザーは (あまり古くないブラウザーも含めて) 第 3 引数がまだ論理値であると仮定しているので、このシナリオをインテリジェントに処理できるようにコードを構築する必要があります。これを行うには、興味のあるオプションごとに機能検出を使用します。

例えば、 `passive` オプションをチェックしたい場合は次のようにします。

```js
let passiveSupported = false;

try {
  const options = {
    get passive() {
      // この関数はブラウザーが passive プロパティに
      // アクセスしようとしたときに呼び出されます。
      passiveSupported = true;
      return false;
    },
  };

  window.addEventListener("test", null, options);
  window.removeEventListener("test", null, options);
} catch (err) {
  passiveSupported = false;
}
```

これは、 `options` オブジェクトを生成し、 `passive` プロパティのゲッター関数を持たせます。ゲッターは、呼ばれた場合に `passiveSupported` フラグを `true` に設定します。つまり、ブラウザーが `passive` プロパティの値を `options` オブジェクトでチェックした場合、 `passiveSupported` は `true` に設定され、そうでなければ `false` のままになります。次に `addEventListener()` を呼び出して、これらのオプションを指定して偽のイベントハンドラーをセットアップし、ブラウザーが第 3 引数としてオブジェクトを認識した場合にオプションがチェックされるようにします。その後、`removeEventListener()` を呼び出して、自分たちで後始末をします。（呼ばれていないイベントリスナーでは `handleEvent()` は無視されることに注意してください。）

この方法で、任意のオプションに対応しているかどうかを確認することができます。上に示したようなコードを使って、そのオプションのゲッターを追加するだけです。

そして、問題のオプションを使用する実際のイベントリスナーを作成したい場合は、次のようにします。

```js
someElement.addEventListener(
  "mouseup",
  handleMouseUp,
  passiveSupported ? { passive: true } : false,
);
```

ここでは、 `mouseup` イベントのリスナーを `someElement` 要素に追加しています。第 3 引数の `passiveSupported` が `true` である場合、 `options` オブジェクトを `passive` を `true` に設定して指定しています。そうでない場合は、論理値を渡す必要があることがわかっているので、 `useCapture` 引数の値として `false` を渡しています。

ご希望であれば、 Modernizr や Detect It のようなサードパーティ製のライブラリーを使用してこのテストを行うことができます。

Web Incubator Community Group の `EventListenerOptions` の記事を参考にしてください。

例
-

### シンプルなリスナーの追加

この例は、要素上でのマウスクリックを監視するための `addEventListener()` の使い方を紹介します。

#### HTML

```html
<table id="outside">
  <tr>
    <td id="t1">one</td>
  </tr>
  <tr>
    <td id="t2">two</td>
  </tr>
</table>
```

#### JavaScript

```js
// t2 の内容を変更する関数
function modifyText() {
  const t2 = document.getElementById("t2");
  const isNodeThree = t2.firstChild.nodeValue === "three";
  t2.firstChild.nodeValue = isNodeThree ? "two" : "three";
}

// イベントリスナーを table に追加
const el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
```

このコードの中で、 `modifyText()` が `addEventListener()` を使用して登録された `click` イベントのリスナーです。表の中のどこかをクリックすると、ハンドラーまでバブリングし、 `modifyText()` が実行されます。

#### 結果

### 中断可能なリスナーの追加

この例では、 `addEventListener()` で `AbortSignal` による中断ができるリスナーを追加する方法を実演しています。

#### HTML

```html
<table id="outside">
  <tr>
    <td id="t1">one</td>
  </tr>
  <tr>
    <td id="t2">two</td>
  </tr>
</table>
```

#### JavaScript

```js
// 中断可能なリスナーを table に追加
const controller = new AbortController();
const el = document.getElementById("outside");
el.addEventListener("click", modifyText, { signal: controller.signal });

// t2 の内容を変更する関数
function modifyText() {
  const t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue === "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
    controller.abort(); // "three" になったらリスナーを削除
  }
}
```

上の例では、2 行目の内容が "three" に変わった後に、 `addEventListener()` に渡した `AbortController` から `abort()` を呼び出すようにコードを変更しました。その結果、クリックイベントを待ち受けするコードがなくなったので、値は永遠に "three" のままとなります。

#### 結果

### 無名関数を使用したイベントリスナー

ここで、無名関数を使用してイベントリスナーに引数を渡す方法を見てみましょう。

#### HTML

```html
<table id="outside">
  <tr>
    <td id="t1">one</td>
  </tr>
  <tr>
    <td id="t2">two</td>
  </tr>
</table>
```

#### JavaScript

```js
// t2 のコンテンツを変更する関数
function modifyText(new\_text) {
  const t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;
}

// イベントリスナーを table に追加する関数
const el = document.getElementById("outside");
el.addEventListener(
  "click",
  function () {
    modifyText("four");
  },
  false,
);
```

なお、リスナーは実際にイベントに応答する `modifyText()` 関数に引数を送信することができるコードをカプセル化している無名関数であることに注意してください。

#### 結果

### アロー関数を使用したイベントリスナー

この例はアロー関数表記を使用して実装された、簡単なイベントリスナーを紹介しています。

#### HTML

```html
<table id="outside">
  <tr>
    <td id="t1">one</td>
  </tr>
  <tr>
    <td id="t2">two</td>
  </tr>
</table>
```

#### JavaScript

```js
// t2 の中身を変更するための関数
function modifyText(new\_text) {
  const t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;
}

// アロー関数で table にイベントリスナーを追加
const el = document.getElementById("outside");
el.addEventListener(
  "click",
  () => {
    modifyText("four");
  },
  false,
);
```

#### 結果

なお、無名関数とアロー関数は似ており、違いは `this` を結び付けるかどうかです。無名関数 (および従来のすべての JavaScript 関数) は固有の `this` を作成するのに対し、アロー関数はそれを含む関数の `this` を継承します。

つまり、アロー関数を使用したときは、それを含む関数の変数や定数をイベントハンドラーで利用することができます。

### options の使い方の例

#### HTML

```html
<div class="outer">
  outer, once & none-once
  <div class="middle" target="\_blank">
    middle, capture & none-capture
    <a class="inner1" href="https://www.mozilla.org" target="\_blank">
      inner1, passive & preventDefault(which is not allowed)
    </a>
    <a class="inner2" href="https://developer.mozilla.org/" target="\_blank">
      inner2, none-passive & preventDefault(not open new page)
    </a>
  </div>
</div>
```

#### CSS

```css
.outer,
.middle,
.inner1,
.inner2 {
  display: block;
  width: 520px;
  padding: 15px;
  margin: 15px;
  text-decoration: none;
}
.outer {
  border: 1px solid red;
  color: red;
}
.middle {
  border: 1px solid green;
  color: green;
  width: 460px;
}
.inner1,
.inner2 {
  border: 1px solid purple;
  color: purple;
  width: 400px;
}
```

#### JavaScript

```js
const outer = document.querySelector(".outer");
const middle = document.querySelector(".middle");
const inner1 = document.querySelector(".inner1");
const inner2 = document.querySelector(".inner2");

const capture = {
  capture: true,
};
const noneCapture = {
  capture: false,
};
const once = {
  once: true,
};
const noneOnce = {
  once: false,
};
const passive = {
  passive: true,
};
const nonePassive = {
  passive: false,
};

outer.addEventListener("click", onceHandler, once);
outer.addEventListener("click", noneOnceHandler, noneOnce);
middle.addEventListener("click", captureHandler, capture);
middle.addEventListener("click", noneCaptureHandler, noneCapture);
inner1.addEventListener("click", passiveHandler, passive);
inner2.addEventListener("click", nonePassiveHandler, nonePassive);

function onceHandler(event) {
  alert("outer, once");
}
function noneOnceHandler(event) {
  alert("outer, none-once, default");
}
function captureHandler(event) {
  //event.stopImmediatePropagation();
  alert("middle, capture");
}
function noneCaptureHandler(event) {
  alert("middle, none-capture, default");
}
function passiveHandler(event) {
  // Unable to preventDefault inside passive event listener invocation.
  event.preventDefault();
  alert("inner1, passive, open new page");
}
function nonePassiveHandler(event) {
  event.preventDefault();
  //event.stopPropagation();
  alert("inner2, none-passive, default, not open new page");
}
```

#### 結果

外側、中央、内側のコンテナーをそれぞれクリックして、オプションがどのように動作するかを確認してください。

`options` オブジェクトで特定の値を使用する前に、ユーザーのブラウザーがその値に対応していることを確認するのが良いでしょう。これらは歴史的にすべてのブラウザーがサポートしてきたわけではない追加要素であるからです。詳細はオプションの対応の安全な検出を参照してください。

### 複数のオプションを持つイベントリスナー

引数の `options` には複数のオプションを設定することができます。次の例では、2 つのオプションを設定しています。

* `passive`: ハンドラーが `preventDefault()` を呼び出さないことを示します。
* `once`: イベントハンドラーが一度だけしか呼び出されないことを保証します。

#### HTML

```html
<button id="example-button">このボタンはクリックされていません。</button>
<button id="reset-button">
  このボタンをクリックすると、最初のボタンがリセットされます。
</button>
```

#### JavaScript

```js
const buttonToBeClicked = document.getElementById("example-button");

const resetButton = document.getElementById("reset-button");

// ボタンの初期化テキスト
const initialText = buttonToBeClicked.textContent;

// ボタンがクリックされた後の内容のテキスト
const clickedText = "このボタンがクリックされました。";

// イベントリスナーのコールバック関数は、リスナーが重複して装着されるのを防ぐため
// イベントリスナーのコールバック関数を巻き上げしています。
function eventListener() {
  buttonToBeClicked.textContent = clickedText;
}

function addListener() {
  buttonToBeClicked.addEventListener("click", eventListener, {
    passive: true,
    once: true,
  });
}

// リセットボタンがクリックされると、例えばボタンがリセットされ、
// その状態が再び更新されるようにします。
resetButton.addEventListener("click", () => {
  buttonToBeClicked.textContent = initialText;
  addListener();
});

addListener();
```

#### 結果

その他の注意事項
--------

### ハンドラー内での "this" の値

一連の類似した要素に対して一般的なハンドラーを使いたい場合のように、イベントハンドラーが実行される要素を参照したいということがたびたびあります。

ハンドラー関数を `addEventListener()` を使って要素に装着したとき、ハンドラーの中の `this` の値は要素への参照となります。これはハンドラーに渡された event 引数の `currentTarget` プロパティの値と同じです。

```js
my_element.addEventListener("click", function (e) {
  console.log(this.className); // logs the className of my\_element
  console.log(e.currentTarget === this); // logs `true`
});
```

アロー関数は独自の `this` コンテキストを持たないことをお忘れなく。

```js
my_element.addEventListener("click", (e) => {
  console.log(this.className); // WARNING: `this` is not `my\_element`
  console.log(e.currentTarget === this); // logs `false`
});
```

イベントハンドラー（例えば `onclick`）が HTML ソース内の要素に指定されていた場合、属性値の JavaScript コードは、 `addEventListener()` を使用するような方法で `this` の値を結び付けたハンドラー関数に置き換えられます。コード内に `this` が現れた場合には、要素への参照を表します。

```html
<table id="my\_table" onclick="console.log(this.id);">
  <!-- `this` refers to the table; logs 'my\_table' -->
  …
</table>
```

`this` の値は、属性値の中のコード*によって呼び出される*関数内では、標準的な規則に従って動作することに注意してください。これは次の例で示されています。

```html
<script>
 function logID() {
 console.log(this.id);
 }
</script>
<table id="my\_table" onclick="logID();">
  <!-- when called, `this` will refer to the global object -->
  …
</table>
```

`this` は `logID()` 内においては、グローバルオブジェクト `Window` (または厳格モードの場合は `undefined` になります。

#### bind() を使用した this の指定

`Function.prototype.bind()` メソッドで、その関数のすべての呼び出しにおいて `this` として使用される値を指定できます。これを使えば、関数がどこから呼び出されるかによって `this` の値が変わってしまうというややこしい問題を簡単に回避できます。ただし、リスナーを後で削除できるように、そのリスナーへの参照を残しておく必要があります。

以下は `bind()` を使った場合と使わない場合の例です。

```js
const Something = function (element) {
  // |this| is a newly created object
  this.name = "Something Good";
  this.onclick1 = function (event) {
    console.log(this.name); // this は element なので undefined になります
  };

  this.onclick2 = function (event) {
    console.log(this.name); // this は新しく生成されたオブジェクトに結び付けられているので、 'Something Good' と出力されます
  };

  // bind によって、固定の `this` コンテキストを onclick2 に割り当てる
  this.onclick2 = this.onclick2.bind(this);

  element.addEventListener("click", this.onclick1, false);
  element.addEventListener("click", this.onclick2, false); // これが仕掛けです
};
const s = new Something(document.body);
```

もうひとつの解決策は、あらゆるイベントを捕捉する `handleEvent()` という特別な関数を使用することです。

```js
const Something = function (element) {
  // |this| is a newly created object
  this.name = "Something Good";
  this.handleEvent = function (event) {
    console.log(this.name); // this は新しく生成されたオブジェクトに結び付けられているので、 'Something Good' と出力されます
    switch (event.type) {
      case "click":
        // 処理
        break;
      case "dblclick":
        // 処理
        break;
    }
  };

  // この場合のリスナーは this であって this.handleEvent でないことに注意してください
  element.addEventListener("click", this, false);
  element.addEventListener("dblclick", this, false);

  // リスナーは適切に削除できます
  element.removeEventListener("click", this, false);
  element.removeEventListener("dblclick", this, false);
};
const s = new Something(document.body);
```

*this* の参照を扱うためのもう一つの方法は、 `EventListener` にアクセスする必要のあるフィールドを含むオブジェクトのメソッドを呼び出す関数を渡すことです。

```js
class SomeClass {
  constructor() {
    this.name = "Something Good";
  }

  register() {
    const that = this;
    window.addEventListener("keydown", (e) => {
      that.someMethod(e);
    });
  }

  someMethod(e) {
    console.log(this.name);
    switch (e.keyCode) {
      case 5:
        // ここにいくらかのコード...
        break;
      case 6:
        // ここにいくらかのコード...
        break;
    }
  }
}

const myObject = new SomeClass();
myObject.register();
```

### イベントリスナーのデータの出し入れ

 イベントリスナーは離島のようなもので、データを渡すのも、ましてや実行後にデータを取り戻すのも至難の業だと思われるかもしれません。
 イベントリスナーは引数を、イベントオブジェクト 1 つしかとらず、これは自動的にリスナーに渡され、返値は無視されます。
 では、どのようにデータを取り込んだり、戻したりすればよいのでしょうか。これには良い方法がいくつかあります。

#### "this" を使用したイベントリスナーへのデータの入力

前述の通り、 `Function.prototype.bind()` を使用すると `this` 参照変数を通じてイベントリスナーに値を渡すことができます。

```js
const myButton = document.getElementById("my-button-id");
const someString = "Data";

myButton.addEventListener(
  "click",
  function () {
    console.log(this); // 期待される値: 'Data'
  }.bind(someString),
);
```

この方法は、イベントリスナーの中からプログラムでイベントリスナーがどの HTML 要素で発生したかを知る必要がない場合に適しています。これを行う主な利点は、実際に引数リストにデータを渡す場合とほぼ同じ方法でイベントリスナーがデータを受け取ることです。

#### 外部スコープのプロパティを使用したイベントリスナーへのデータの入力

外部スコープに（`const`, `let` を付けた）変数宣言が含まれている場合、そのスコープで宣言されたすべての内部関数はその変数にアクセスすることができます（外部関数/内部関数についてはこちらを、変数スコープについてはこちらを参照してください）。したがって、イベントリスナーの外部からデータにアクセスする最も簡単な方法の 1 つは、イベントリスナーが宣言されているスコープにアクセスできるようにすることです。

```js
const myButton = document.getElementById("my-button-id");
let someString = "Data";

myButton.addEventListener("click", () => {
  console.log(someString); // 期待される値: 'Data'

  someString = "Data Again";
});

console.log(someString); // 期待される値: 'Data' (will never output 'Data Again')
```

**メモ:** 内側のスコープは外側のスコープにある `const`, `let` 変数にアクセスすることができますが、イベントリスナーの定義後に、同じ外側のスコープ内でこれらの変数にアクセスできるようになることは期待できません。なぜでしょうか？単純に、イベントリスナーが実行される頃には、イベントリスナーが定義されたスコープは既に実行を終了しているからです。

#### オブジェクトを用いたイベントリスナーのデータの出し入れ

JavaScript のほとんどの関数とは異なり、オブジェクトはそのオブジェクトを参照する変数がメモリー内に存在する限り、メモリー内に保持されます。それに加えて、オブジェクトはプロパティを持つことができ、参照によって渡すことができることから、スコープ間でデータを共有するための有力な候補となります。これについて調べてみましょう。

**メモ:** JavaScript の関数は厳密にはオブジェクトです。 (そのため、プロパティを持つことができ、メモリー内に永続的に存在する変数に代入されていれば、実行終了後もメモリー内に保持されます。)

オブジェクトを参照する変数がメモリーに存在する限り、オブジェクトのプロパティを使用してメモリーにデータを格納することができるので、実際にそれらを使用して、イベントリスナーにデータを渡し、イベントハンドラーが実行された後でデータに変更があった場合には、それを戻すことができます。この例を考えてみましょう。

```js
const myButton = document.getElementById("my-button-id");
const someObject = { aProperty: "Data" };

myButton.addEventListener("click", () => {
  console.log(someObject.aProperty); // 期待される値: 'Data'

  someObject.aProperty = "Data Again"; // 値を変更
});

setInterval(() => {
  if (someObject.aProperty === "Data Again") {
    console.log("Data Again: True");
    someObject.aProperty = "Data"; // 次のイベントの実行を待つために値を初期化
  }
}, 5000);
```

この例では、イベントリスナーとインターバル関数の両方が定義されているスコープは、 `someObject.aProperty` の元の値が変更される前に実行を終了していたとしても、イベントリスナーとインターバル関数の両方で `someObject` がメモリー内に (*参照*によって) 持続するため、両方とも同じデータにアクセスできます (つまり、一方がデータを変更したときに、もう一方がその変更に対応できます)。

**メモ:** オブジェクトは参照で変数に格納されます。つまり、実際のデータのメモリーの場所だけが変数に格納されます。とりわけ、これはオブジェクトを「格納」する変数が、実際に同じオブジェクト参照が代入 (「格納」) されている他の変数に影響を与えることができるということです。 2 つの変数が同じオブジェクトを参照している場合 (例えば、 `let a = b = {aProperty: 'Yeah'};`)、どちらかから変数のデータを変更すると、もう一方の変数に影響を与えます。

**メモ:** オブジェクトは参照によって変数に格納されているので、関数の実行を停止した後も、関数からオブジェクトを返す (データを失わないようにメモリーに保存しておく) ことができます。

### メモリーの問題

```js
const elts = document.getElementsByTagName("\*");

// ケース 1
for (const elt of elts) {
  elt.addEventListener(
    "click",
    (e) => {
      // 何かを行う
    },
    false,
  );
}

// ケース 2
function processEvent(e) {
  // 何かを行う
}

for (const elt of elts) {
  elt.addEventListener("click", processEvent, false);
}
```

上記の 1 つ目のケースでは、ループの繰り返しごとに新しい（無名の）ハンドラー関数が作成されます。一方、 2 つ目のケースでは、以前に宣言した同じ関数がイベントハンドラーとして使用され、作成されるハンドラー関数が 1 つであるため、メモリー消費量が少なくなります。さらに、最初のケースでは、無名関数への参照が保持されないため、 `removeEventListener()` を呼び出すことができません（ここでは、ループが生成する可能性がある複数の無名関数への参照が保持されません）。2 番目のケースでは、`processEvent` が関数の参照なので、`myElement.removeEventListener("click", processEvent, false)` を実行することが可能です。

実は、メモリー消費に関しては、関数参照を保持しないことが本当の問題ではなく、むしろ、*静的*な関数参照を保持しないことが問題なのです。

### パッシブリスナーによるスクロールの性能改善

以下の例にあるように、`passive` の値を `true` に設定すると、パフォーマンスを最適化し、アプリケーションのパフォーマンスが劇的に向上する可能性があります。

```js
/\* 機能検出 \*/
let passiveIfSupported = false;

try {
  window.addEventListener(
    "test",
    null,
    Object.defineProperty({}, "passive", {
      get() {
        passiveIfSupported = { passive: true };
      },
    }),
  );
} catch (err) {}

window.addEventListener(
  "scroll",
  (event) => {
    /\* 何かを行う \*/
    // event.preventDefault(); は使用できない
  },
  passiveIfSupported,
);
```

`addEventListener()` の仕様では、`passive` オプションの既定値は常に `false` です。しかし、これはタッチイベントやホイールイベントを扱うイベントリスナーがスクロールを処理しようとしている間にブラウザーのメインスレッドをブロックする可能性をもたらすため、スクロール処理中の性能が大幅に低下する結果になる可能性があります。

この問題を防ぐため、Safari 以外のブラウザーでは、文書レベルのノードである `Window`、`Document`、`Document.body` のに対する `wheel`、`mousewheel`、`touchstart`、`touchmove` イベントの `passive` オプションの既定値が `true` に変更されました。これにより、イベントリスナーがイベントをキャンセルすることができなくなるため、ユーザーがスクロールしている間、ページレンダリングをブロックすることがなくなります。

**メモ:** この変更された動作を実装しているブラウザー（およびそれらのブラウザーのバージョン）を知りたい場合は、下記の互換性一覧表を参照してください。

そのため、その動作を上書きして、すべてのブラウザーで `passive` オプションが `false` になるようにしたい場合は、（既定値に頼らず）明示的にオプションを `false` に設定する必要があります。

 基本的な `scroll` イベントの `passive` の値を気にする必要はありません。
 もともとキャンセル不可であるため、イベントリスナーはいずれにせよページのレンダリングをブロックすることはありません。

### 古いブラウザー

`addEventListener()` の `options` 引数に対応していない古いブラウザーでは、正しく機能検出をせずに使おうとすると、 `useCapture` 引数が使用できないことがあります。

仕様書
---

| Specification |
| --- |
| DOM Standard # ref-for-dom-eventtarget-addeventlistener③ |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `EventTarget.removeEventListener()`
* イベントの作成と起動
* イベントハンドラー内での `this` の使用方法のさらに詳細な解説


EventTarget: EventTarget() コンストラクター - Web API

EventTarget: EventTarget() コンストラクター
===================================

**`EventTarget()`** コンストラクターは、新しい `EventTarget` オブジェクトのインスタンスを作成します。

**メモ:** このコンストラクターを明示的に呼び出すことは、非常にまれです。ほとんどの場合、このコンストラクターは `EventTarget` から派生したオブジェクトのコンストラクターの中で、 `super` キーワードによって使用されます。

構文
--

```js
new EventTarget()
```

### 引数

なし。

### 返値

`EventTarget` オブジェクトのインスタンス。

例
-

```js
class MyEventTarget extends EventTarget {
  constructor(mySecret) {
    super();
    this._secret = mySecret;
  }

  get secret() {
    return this._secret;
  }
}

let myEventTarget = new MyEventTarget(5);
let value = myEventTarget.secret; // === 5
myEventTarget.addEventListener("foo", (e) => {
  myEventTarget._secret = e.detail;
});

let event = new CustomEvent("foo", { detail: 7 });
myEventTarget.dispatchEvent(event);
let newValue = myEventTarget.secret; // === 7
```

仕様書
---

| Specification |
| --- |
| DOM Standard # ref-for-dom-eventtarget-eventtarget① |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `EventTarget`


EventTarget: dispatchEvent() メソッド - Web API

EventTarget: dispatchEvent() メソッド
=================================

**`dispatchEvent()`** は `EventTarget` のメソッドで、 `Event` をそのオブジェクトへ送り、関連するイベントリスナーを（同期的に）適切に起動させます。通常のイベント処理ルール（キャプチャとオプションのバブリングフェーズを含む）は `dispatchEvent()` で手動で配信されたイベントにも適用されます。

`dispatchEvent()` の呼び出しは、イベントを発行させるための最後のステップです。イベントは既に `Event()` コンストラクターを使って作成され、初期化されているはずです。

**メモ:** このメソッドを呼び出すとき、 `Event.target` プロパティは現在の `EventTarget` に初期化されます。

「ネイティブ」イベントがブラウザーによって発生し、イベントループを介して非同期にイベントハンドラーを呼び出すのとは異なり、 `dispatchEvent()` はイベントハンドラーを*同期的に*呼び出します。適用可能なすべてのイベントハンドラが呼び出され、 `dispatchEvent()` から戻る前に返されます。

構文
--

```js
dispatchEvent(event)
```

### 引数

`event`

配信する `Event` オブジェクトです。この `Event.target` プロパティは現在の `EventTarget` に設定されます。

### 返値

`event` がキャンセル可能で、かつ `event` を受け取ったイベントハンドラーの少なくとも 1 つが `Event.preventDefault()` を呼び出した場合は `false` となります。それ以外の場合は `true` です。

### 例外

`InvalidStateError` `DomException`

イベントの初期化時に、イベントの種類が指定されなかった場合に発生します。

**警告:** イベントハンドラーで発生した例外は、捕捉されない例外として報告されます。イベントハンドラーはネストされたコールスタック上で実行されます。イベントハンドラーが完了するまで呼び出し元はブロックされますが、例外は呼び出し元まで伝搬しません。

例
-

イベントの作成と起動 を参照してください。

仕様書
---

| Specification |
| --- |
| DOM Standard # ref-for-dom-eventtarget-dispatchevent③ |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* Event オブジェクトリファレンス


EventTarget: removeEventListener() メソッド - Web API

EventTarget: removeEventListener() メソッド
=======================================

**`removeEventListener()`** は `EventTarget` インターフェイスのメソッドで、以前に `EventTarget.addEventListener()` で登録されたイベントリスナーを取り外します。
 取り外されるイベントリスナーはイベントの型、イベントリスナー関数そのもの、照合プロセスに影響を与えるさまざまな任意のオプションを使用して識別します。
 取り外すイベントリスナーの照合を参照してください。

`removeEventListener()` を呼び出したときの引数で `EventTarget` に登録されているイベントリスナーが特定できなかった場合は、何も起こりません。

イベントリスナーが `EventTarget` の他のリスナーのイベント処理中に外された場合、イベントによって起動させることはありません。しかし、再接続は可能です。

**警告:** リスナーが *capture* フラグを設定したものと設定しないものの 2 つ登録されている場合、それぞれを別々に取り外す必要があります。キャプチャするリスナーを取り外しても、同じリスナーのキャプチャしないバージョンには影響しませんし、その逆も同様です。

イベントリスナーを取り外すには、 `AbortSignal` を `addEventListener()` に渡して、後でそのシグナルを所有するコントローラーで `abort()` を呼び出して行うことも可能です。

構文
--

```js
removeEventListener(type, listener)
removeEventListener(type, listener, options)
removeEventListener(type, listener, useCapture)
```

### 引数

`type`

文字列で、イベントリスナーを取り外すイベントの種類を表します。

`listener`

イベントターゲットから取り外すイベントハンドラーのイベントリスナー関数です。

`options` 省略可

イベントリスナーに関する特性を指定する、オプションのオブジェクトです。

次のオプションが使用できます。

* `capture`: 論理値で、取り外すイベントリスナーがキャプチャリスナーとして登録されているか否かを指定します。この引数がない場合、既定の値として `false` が想定される。

`useCapture` 省略可

取り外すイベントリスナーがキャプチャリスナーとして登録されているかを指定します。この引数を省略した場合は、既定値の `false` であるとみなします。

### 返値

なし。

### 取り外すイベントリスナーの照合

以前に `addEventListener()` を呼び出して追加したイベントリスナーがある場合、最終的にそれを取り外す必要がある場合があります。当然ながら、同じ `type` と `listener` 引数を `removeEventListener()` には指定する必要があります。しかし、 `options` や `useCapture` 引数はどうでしょうか。

`addEventListener()` は、オプションが異なれば同じリスナーを同じ種類に複数回追加することができますが、 `removeEventListener()` がチェックするオプションは `capture`/`useCapture` フラグのみとなります。この値は `removeEventListener()` で一致するためには一致していなければなりませんが、他の値は一致していなくてもかまいません。

例えば、以下の `addEventListener()` で考えましょう。

```js
element.addEventListener("mousedown", handleMouseDown, true);
```

そして、以下 2 つの `removeEventListener()` の呼び出しについて考えましょう。

```js
element.removeEventListener("mousedown", handleMouseDown, false); // 失敗
element.removeEventListener("mousedown", handleMouseDown, true); // 成功
```

1 番目の呼び出しは、 `useCapture` の値が異なるため失敗します。2 番目は、`useCapture` が一致するので成功します。

次に、以下の呼び出しを考えましょう。

```js
element.addEventListener("mousedown", handleMouseDown, { passive: true });
```

ここでは `options` で `passive` を `true` に設定して指定していますが、他のオプションは既定値の `false` のままです。

では、以下の `removeEventListener()` の呼び出しについて、順番に見ていきましょう。`capture` または `useCapture` が `true` であるものは失敗して、そのほかは成功します。

`capture` の設定だけが `removeEventListener()` に関与します。

```js
element.removeEventListener("mousedown", handleMouseDown, { passive: true }); // 成功
element.removeEventListener("mousedown", handleMouseDown, { capture: false }); // 成功
element.removeEventListener("mousedown", handleMouseDown, { capture: true }); // 失敗
element.removeEventListener("mousedown", handleMouseDown, { passive: false }); // 成功
element.removeEventListener("mousedown", handleMouseDown, false); // 成功
element.removeEventListener("mousedown", handleMouseDown, true); // 失敗
```

この点については、いくつかのブラウザのリリースで一貫性がないことに注意してください。特に理由がない限り、`addEventListener()` の呼び出しで使用したのと同じ値を `removeEventListener()` の呼び出しでも使用することが賢明でしょう。

例
-

この例は、`mouseover` ベースのイベントリスナーを追加して `click` ベースのイベントリスナーを取り外す方法を示します。

```js
const body = document.querySelector("body");
const clickTarget = document.getElementById("click-target");
const mouseOverTarget = document.getElementById("mouse-over-target");

let toggle = false;
function makeBackgroundYellow() {
  body.style.backgroundColor = toggle ? "white" : "yellow";

  toggle = !toggle;
}

clickTarget.addEventListener("click", makeBackgroundYellow, false);

mouseOverTarget.addEventListener("mouseover", () => {
  clickTarget.removeEventListener("click", makeBackgroundYellow, false);
});
```

仕様書
---

| Specification |
| --- |
| DOM Standard # ref-for-dom-eventtarget-removeeventlistener② |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `EventTarget.addEventListener()`


CSS.registerProperty() - Web API

CSS.registerProperty()
======================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**`CSS.registerProperty()`** メソッドは`カスタムプロパティ`を登録し、プロパティ型のチェック、既定値、値の継承の有無の指定を行うことができます。

カスタムプロパティを登録すると、許される型は何か、その値を継承するかどうか、既定値は何かといったカスタムプロパティの動作ををブラウザーに指示することができます。

構文
--

```js
CSS.registerProperty(PropertyDefinition)
```

### 引数

次のメンバーを設定することができる `PropertyDefinition` 辞書オブジェクトです。

`name`

定義するプロパティの名前を示す文字列です。

`syntax` 省略可

定義されたプロパティの期待される構文を表す文字列です。 既定値は `"*"` です。

`inherits`

定義されたプロパティを継承するか (`true`)、否か (`false`) を定義する論理値。 既定値は `false` です。

`initialValue` 省略可

定義されたプロパティの初期値を表す文字列です。

### 返値

`undefined` です。

### 例外

`InvalidModificationError` `DOMException`

指定された `name` がすでに登録されている場合。

`SyntaxError` `DOMException`

指定された `name` が（`--foo` のように、 2 つのダッシュで始まる）有効なカスタムプロパティ名ではない場合。

`TypeError`

必須の辞書メンバーの `name` または `inherits`、あるいはその両方が指定されていない場合。

例
-

次の例では、`カスタムプロパティ`の `--my-color` を、 `registerProperty()` を使用して色として登録し、既定値を指定して、その値を継承しないようにします。

```js
window.CSS.registerProperty({
  name: "--my-color",
  syntax: "<color>",
  inherits: false,
  initialValue: "#c0ffee",
});
```

この例では、カスタムプロパティ `--my-color` が構文 `<color>` を使用して登録されます。 これで、このプロパティを使用して、ポインターを当てたりフォーカスを与えたりするとグラデーションをトランジションで変化させることができます。 登録されたプロパティではトランジションが機能しますが、未登録のプロパティでは機能しないことに注意してください。

```css
.registered {
  --my-color: #c0ffee;
  background-image: linear-gradient(to right, #fff, var(--my-color));
  transition: --my-color 1s ease-in-out;
}

.registered:hover,
.registered:focus {
  --my-color: #b4d455;
}

.unregistered {
  --unregistered: #c0ffee;
  background-image: linear-gradient(to right, #fff, var(--unregistered));
  transition: --unregistered 1s ease-in-out;
}

.unregistered:hover,
.unregistered:focus {
  --unregistered: #b4d455;
}
button {
  font-size: 3vw;
}
```

これらのスタイルをいくつかのボタンに追加できます。

```html
<button class="registered">Background Registered</button>
<button class="unregistered">Background Not Registered</button>
```

仕様書
---

| Specification |
| --- |
| CSS Properties and Values API Level 1 # the-registerproperty-function |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* CSS プロパティと値 API の使用
* `CSS`
* `CSS.supports_static`
* `CSS.escape_static`
* CSS ファクトリー関数


CSS: highlights 静的プロパティ - Web API

CSS: highlights 静的プロパティ
=======================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

**`highlights`** は `CSS` インターフェイスは静的な読み取り専用プロパティであり、interface は、CSS カスタムハイライト API (en-US) を使用して任意のテキスト範囲をスタイル設定するために用いる `HighlightRegistry` へのアクセス手段を提供します。

値
-

`HighlightRegistry` (en-US) オブジェクトです。

例
-

次の例は、複数のテキスト範囲を作成し、そのテキスト範囲に対して `Highlight` オブジェクトを作成し、このハイライトを `HighlightRegistry` に登録し、最後に `::highlight()` (en-US) 擬似要素を使用してテキスト範囲にスタイルを設定する例を示しています。

```js
const parentNode = document.getElementById("foo");

const range1 = new Range();
range1.setStart(parentNode, 10);
range1.setEnd(parentNode, 20);

const range2 = new Range();
range2.setStart(parentNode, 40);
range2.setEnd(parentNode, 60);

const myCustomHighlight = new Highlight(range1, range2);

CSS.highlights.set("my-custom-highlight", myCustomHighlight);
```

```css
::highlight(my-custom-highlight) {
  background-color: yellow;
  color: black;
}
```

仕様書
---

| Specification |
| --- |
| CSS Custom Highlight API Module Level 1 # dom-css-highlights |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* CSS カスタムハイライト API (en-US)
* CSS Custom Highlight API: The Future of Highlighting Text Ranges on the Web


CSS: supports() 静的メソッド - Web API

CSS: supports() 静的メソッド
======================

**`CSS.supports()`** メソッドは、ブラウザーが指定された CSS 機能に対応しているかどうかを論理値で返します。

構文
--

```js
CSS.supports(propertyName, value)
CSS.supports(supportCondition)
```

### 引数

引数の組み合わせが 2 種類あります。1 つ目は、対応しているかどうかをテストする*プロパティと値*を指定することができます。

`propertyName`

文字列で、チェックする CSS プロパティの名前が入ります。

`value`

文字列で、チェックする CSS プロパティの値が入ります。

2 つ目の構文は 1 つの引数を取り、`@supports` の条件と照合します。

`supportCondition`

文字列で、チェックする条件が入ります。

### 返値

ブラウザーがそのルールに対応しているのであれば `true`、そうでなければ `false` です。

例
-

```js
result = CSS.supports("text-decoration-style", "blink");
result = CSS.supports("display: flex");
result = CSS.supports("(--foo: red)");

result = CSS.supports(
  "(transform-style: preserve) or (-moz-transform-style: preserve) or (-webkit-transform-style: preserve)",
);

// 結果は true または false
```

仕様書
---

| Specification |
| --- |
| CSS Conditional Rules Module Level 3 # ref-for-dom-css-supports |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `@supports` アットルールは、同様の機能を宣言的な方法で行うことができます。
* `CSSSupportsRule` は CSSOM のクラスで、 `@supports` アットルールを操作することができます。


CSS 数値ファクトリー関数 - Web API

CSS 数値ファクトリー関数
==============

**CSS 数値ファクトリー関数**、たとえば `CSS.em()` や `CSS.turn()` は、単位を使用するメソッド名とし、数値を引数とした値の CSSUnitValues (en-US) を返すもので、このメソッドを使用すると、数値引数で単位を設定することができます。これらの関数は `CSSUnitValue()` (en-US) コンストラクターを使うよりも冗長でなく新しい数値を生成します。

構文
--

```js
CSS.number(number)
CSS.percent(number)

// <length>
CSS.em(number)
CSS.ex(number)
CSS.ch(number)
CSS.ic(number)
CSS.rem(number)
CSS.lh(number)
CSS.rlh(number)
CSS.vw(number)
CSS.vh(number)
CSS.vi(number)
CSS.vb(number)
CSS.vmin(number)
CSS.vmax(number)
CSS.cm(number)
CSS.mm(number)
CSS.Q(number)
CSS.in(number)
CSS.pt(number)
CSS.pc(number)
CSS.px(number)

// <angle>
CSS.deg(number)
CSS.grad(number)
CSS.rad(number)
CSS.turn(number)

// <time>
CSS.s(number)
CSS.ms(number)

// <frequency>
CSS.Hz(number)
CSS.kHz(number)

// <resolution>
CSS.dpi(number)
CSS.dpcm(number)
CSS.dppx(number)

// <flex>
CSS.fr(number)
```

例
-

数値ファクトリー関数の `CSS.vmax()` を使用して `CSSUnitValue` (en-US) を作成します。

```js
const height = CSS.vmax(50);

console.log(height); // CSSUnitValue {value: 50, unit: "vmax"}
console.log(height.value); // 50
console.log(height.unit); // vmax
```

この例では、要素のマージンを `CSS.px()` ファクトリー関数で設定します。

```js
myElement.attributeStyleMap.set("margin", CSS.px(40));
const currentMargin = myElement.attributeStyleMap.get("margin");
console.log(currentMargin.value, currentMargin.unit); // 40, 'px'
```

仕様書
---

| Specification |
| --- |
| CSS Object Model (CSSOM) # namespacedef-css |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `CSSUnitValue()` (en-US)


CSS: paintWorklet 静的プロパティ - Web API

CSS: paintWorklet 静的プロパティ
=========================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

**安全なコンテキスト用:** この機能は一部またはすべての対応しているブラウザーにおいて、安全なコンテキスト (HTTPS) でのみ利用できます。

**`paintWorklet`** は `CSS` インターフェイスの静的な読み取り専用プロパティで、ペイントワークレットへのアクセスを提供します。これは、CSS のプロパティが画像ファイルを期待する場所においてプログラムで画像を生成します。

値
-

関連付けられた `Worklet` オブジェクトです。

例
-

次の例は、js ファイルからペイントワークレットを読み込む方法を示しており、機能検出によって読み込みます。

```js
if ("paintWorklet" in CSS) {
  CSS.paintWorklet.addModule("checkerboard.js");
}
```

仕様書
---

| Specification |
| --- |
| CSS Painting API Level 1 # ref-for-dom-css-paintworklet |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* CSS 描画 API
* Houdini API


CSS: escape() 静的メソッド - Web API

CSS: escape() 静的メソッド
====================

**`CSS.escape()`** は静的メソッドで、 CSS セレクターの一部として使用するために引数として渡されるエスケープ処理された文字列の入った文字列を返します。

構文
--

```js
CSS.escape(str)
```

### 引数

`str`

エスケープ処理する文字列です。

### 返値

エスケープされた文字列です。

例
-

### 基本的な結果

```js
CSS.escape(".foo#bar"); // "\.foo\#bar"
CSS.escape("()[]{}"); // "\(\)\[\]\{\}"
CSS.escape('--a'); // "--a"
CSS.escape(0); // "\30 " （'0' の Unicode コードポイントは 30）
CSS.escape('\0'); // "\ufffd" （Unicode REPLACEMENT CHARACTER）
```

### コンテキスト内での使用

セレクターの一部として使用するために文字列をエスケープするには、 `escape()` メソッドを使用します。

```js
const element = document.querySelector(`#${CSS.escape(id)} > img`);
```

`escape()` メソッドは文字列のエスケープにも使えますが、厳密にはエスケープする必要がない文字もエスケープしてしまいます。

```js
const element = document.querySelector(`a[href="#${CSS.escape(fragment)}"]`);
```

仕様書
---

| Specification |
| --- |
| CSS Object Model (CSSOM) # the-css.escape()-method |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* この静的メソッドが所属する `CSS` インターフェイス
* CSS.escape のポリフィル


PresentationAvailability: value プロパティ - Web API

PresentationAvailability: value プロパティ
=====================================

**Experimental:** **これは実験的な機能です。**
本番で使用する前にブラウザー互換性一覧表をチェックしてください。

**`value`** 属性は設定された最新の値を返さ ***なければなりません***。この値は利用可能なプレゼンテーション用画面のリストを監視するアルゴリズムにより更新されます。

`onchange` 属性はイベントハンドラーであり、対応するイベントハンドラーのイベントの種類は `change` です。

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSPropertyRule.name - Web API

CSSPropertyRule.name
====================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**`name`** は `CSSPropertyRule` インターフェイスの読み取り専用プロパティで、これはプロパティ名を表します。これは `@property` ルールの前置き部分においてカスタムプロパティに指定された名前をシリアライズしたものです。

値
-

A string.

例
-

このスタイルシートには、単一の `@property` ルールが格納されています。最初に返される `CSSRule` は、このルールを表す `CSSPropertyRule` となります。 `name` プロパティは文字列 `"--property-name"` を返します。この文字列は、 CSS でカスタムプロパティに指定された名前です。

```css
@property --property-name {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}
```

```js
let myRules = document.styleSheets[0].cssRules;
console.log(myRules[0].name); //the string "--property-name"
```

仕様書
---

| Specification |
| --- |
| CSS Properties and Values API Level 1 # dom-csspropertyrule-name |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSPropertyRule.inherits - Web API

CSSPropertyRule.inherits
========================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**`inherits`** は `CSSPropertyRule` インターフェイスの読み取り専用プロパティで、 `@property` ルールで表現されているカスタムプロパティ登録の継承フラグ、つまり、そのプロパティが既定値では継承されるかどうかを記述した論理値を返します。

値
-

論理値です。

例
-

このスタイルシートには、単一の `@property` ルールが格納されています。最初に返される `CSSRule` は、このルールを表す `CSSPropertyRule` となります。 `inherits` プロパティは論理値 `false` を返します。これは CSS の `inherits` プロパティの値です。

```css
@property --property-name {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}
```

```js
let myRules = document.styleSheets[0].cssRules;
console.log(myRules[0].inherits); //returns false
```

仕様書
---

| Specification |
| --- |
| CSS Properties and Values API Level 1 # dom-csspropertyrule-inherits |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSPropertyRule.syntax - Web API

CSSPropertyRule.syntax
======================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**`syntax`** は `CSSPropertyRule` インターフェイスの読み取り専用プロパティで、 これは、 `@property` ルールによって表されるカスタムプロパティ登録のリテラル構文を返し、プロパティの値が計算値の時点でどのように解釈されるかを制御するものです。

値
-

文字列です。

例
-

このスタイルシートには、単一の `@property` ルールが格納されています。最初に返される `CSSRule` は、このルールを表す `CSSPropertyRule` となります。 `syntax` プロパティはリテラル文字列の `"<color>"` を返します。

```css
@property --property-name {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}
```

```js
let myRules = document.styleSheets[0].cssRules;
console.log(myRules[0].syntax); //the string "<color>"
```

仕様書
---

| Specification |
| --- |
| CSS Properties and Values API Level 1 # dom-csspropertyrule-syntax |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.