今からでも追いつける！　JavaScriptの「標準ライブラリ」を学ぶ

標準ライブラリは、大ざっぱに言えばプログラミング言語に標準で備え付けられている機能群です。多くのプログラミング言語では、形態は様々ですが何らかの形で標準ライブラリが備え付けられています。標準ライブラリはプログラミング言語の一部であり、言語のバージョンアップに伴って標準ライブラリに機能が追加されることは良くあります。

この記事ではJavaScriptにおける「標準ライブラリ」がどんなものなのか、その歴史的経緯なども交えながら解説します。「標準ライブラリ？　何それ」という方も「そんなの基本だろｗ解説されなくても分かるわｗ」という方もぜひ一読していってください。

なお、記事執筆時点では標準ライブラリに関することは**何一つとして標準化が完了しておらず、内容が今後大きく変化する可能性が十分にあります**。この記事で概要を理解したあと、いざ使用する際にはご自分で最新の情報を調べたほうがよいでしょう。

**お詫びと訂正（2019年8月14日）**：　この記事では「標準ライブラリ」を紹介していましたが、プロポーザルの名前が「標準ライブラリ (standard library)」から「**組み込みモジュール** (built-in modules)」に変わってしまいました。個人的には「標準ライブラリ」という釣りっぽいけど釣りじゃない名前が好きだったのになどと考えており大変申し訳ありません。時間があるときに記事を書き直しますが、ひとまず「標準ライブラリ」は「組み込みモジュール」に読み替えてお読みください。名前は変わりましたが機能の内容自体は変わっていません。

## 広義の標準ライブラリ

JavaScriptに標準で備え付けられている機能といえば、この記事を読んでいる皆さんはいろいろなものが思い浮かぶことでしょう。例えば`Math`などはそれっぽいですね。小数点以下を切り捨てる`Math.floor`など、さまざまな関数や定数が`Math`オブジェクトのプロパティとして提供されています。この`Math`自体はグローバル変数として存在しています。他にも日時を表現する`Date`オブジェクト、バイナリデータを扱える`ArrayBuffer`や`Uint8Array`、グローバル変数として存在する`parseInt`関数[^Number_parseInt]などもよく使いますね。このように、JavaScriptの組み込みの言語機能はほとんどがグローバル変数として提供されています。

[^Number_parseInt]: 新しい`Number.parseInt`のほうが推奨されますが、グローバル変数の`parseInt`のほうが広く使われているように思えます。後方互換性の話もありますし。

これらはJavaScript (ECMAScript) の言語仕様で定義されている機能ですから、ここまでの話でいうとこれがJavaScriptの標準ライブラリであると言えるかもしれません。しかし、**この記事でいう「標準ライブラリ」はこれのことではありません**。このようにグローバル変数を介して提供される言語機能をこの記事では**広義の標準ライブラリ**ということにしていますが、この記事で解説したいのはこの広義の標準ライブラリではありません。

今後も様々な機能が追加されていくと期待されているJavaScriptにおいて、このような（グローバル変数を用いた）方式での機能拡張というのは限界が来ています。それを解決するのが、この記事で解説する「標準ライブラリ」、すなわち**狭義の標準ライブラリ**です。なお、広義・狭義という分け方はこの記事独自のものであり、一般に通用する言い方ではないかもしれませんのでご注意ください。

## 復習：モジュール

今回解説する標準ライブラリには**モジュール**が大きく関わっていますので、ちょっとモジュールの解説を挟みます。もう知ってるよという方は適当に飛ばしてください。モジュールはES2015でJavaScriptに追加された言語機能で、`import`文と`export`文という2つの構文が特徴です。ざっくり言えば1つのjsファイルが1つの**モジュール**となり、`export`文ではそのモジュールから**エクスポート**される関数やその他の値[^module_export]を宣言します。そして、`import`文は他のモジュールからエクスポートされるものを**インポート**、すなわち取り込んで利用することができます。

[^module_export]: 正確にはエクスポートされているのはバインディングであると言うべきですが。

以下は2つのファイルからなるモジュール利用例です。

```js:foo.js
export function fooFunction(x) {
    return x * 2;
}
```

```js:index.js
import { fooFunction } from './foo.js';

console.log(fooFunction(123)); // 246
```

この例では`foo.js`が`export`文で関数`fooFunction`をエクスポートしています。`index.js`は`foo.js`から`fooFunction`をインポートして利用しています。

今回注目していただきたいのは、`import`文で読み込む対象のモジュールがどのように指定されているかです。この例ではインポート元を`"./foo.js"`としており、明らかにこれは同じディレクトリにある`foo.js`を読み込むという意味ですね。

`import`文で指定されたインポート元をどのように解釈するかは実行環境に委ねられています。現在主要なJavaScriptの実行環境はざっくり**ブラウザ**と**node.js**の2つですが、それぞれで可能なインポート元が異なってきます[^module_bundlers]。

[^module_bundlers]: 現段階だとこれらの実行環境で直接モジュールを動かすよりも、WebpackやRollupなどのバンドラへの入力として使うほうが馴染み深いという方が多いでしょうが、その話はややこしくなるので今回は避けることにします。

ブラウザの場合は話が簡単で、インポート元は**URL**です。上の例は相対URLと見なせますので、ブラウザで動作します。絶対URLも`import React from "https://dev.jspm.io/react";`のように使用できます。

一方、node.jsはもう少し話が複雑です。`./foo.js`のような相対パスはnode.jsでも動作する[^node_extentions]ほか、`./foo`のように拡張子を省略できるのが特徴的です。また、`import React from "react";`のようにパスではなくモジュール名を指定することで`node_modules`から該当モジュールを読み込むことも可能です。一方、`http://`などのスキームを用いてモジュールをインターネット上から読み込むことはできません。

[^node_extentions]: ただし、node.jsでは`"type":"module"`を持つpackage.jsonを用意するかモジュールの拡張子を`.js`ではなく`.mjs`にする必要があります。


## 結局標準ライブラリとは何か

では、いよいよ本題に入ります。

結論を一言で言うならば、この記事で紹介する**標準ライブラリ**（狭義の標準ライブラリ）は**特別な名前で提供されるモジュール**です。具体例などはあとでお見せしますが、特別な名前というのは`js:`で始まるモジュール名です。標準ライブラリのモジュールは処理系に組み込まれており、特に事前の準備なく`import`文で読み込むことができます。例えば、`temporal`というモジュールが標準ライブラリに含まれているとすると、`temporal`を使用したい場合は以下のようにします[^temporal_proposal]。

[^temporal_proposal]: 標準ライブラリへの導入が確定しているモジュールなどというものは存在しないので仮に`temporal`を使用しています。[temporalのプロポーザル](https://github.com/tc39/proposal-temporal)に“a built in module”と書いてあったので多分標準モジュールになるんじゃないかと思いますが、よく分かりません。

```js
// 標準ライブラリのtemporalモジュールからCivilDateをインポート
import { CivilDate } from 'js:temporal';
```

先ほども説明したように、標準ライブラリのモジュールは`js:モジュール名`という名前を用いて`import`文で読み込みます。ポイントは、この`js:`で始まる形式は上で説明した既存のインポート元指定方法（URLやモジュール名など）には当てはまらないということです[^alt_module_id_npm]。これにより、モジュールを用いた従来のコードを壊すことなく新しいモジュールを追加できるというわけです。さらに、この`js:`という文字列は[IANAに登録されることになります](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml)。これにより、将来的に`js:`で始まるURL（というかURI）が他の用途で使用される事態が回避されます。

[^alt_module_id_npm]: あとでもう少し詳しく説明しますが、標準ライブラリのモジュールを表す他の案としては全く新規のもの以外にもnpmのscoped modulesの記法を流用した`@std/temporal`のようなものが提案されています。

標準ライブラリとしては、JavaScript本体の言語機能に加えてブラウザ向けの機能なども標準ライブラリとして扱うことができるという方向で話が進んでいます。そうなると、全てを`js:`の中に入れていいのか、それともブラウザ向けは`html:`とかnode.js向けは`node:`というように名前空間を分けたほうがいいのかという疑問が発生します。この問題については[議論があります](https://github.com/tc39/proposal-javascript-standard-library/issues/14)が、まだ答えは出ていないようです。

### 標準ライブラリのプロポーザル
今さらですが、この記事で述べている標準ライブラリというのは、以下のプロポーザル（現在Stage 1）です。プロポーザルということはまだJavaScriptの仕様に正式採用される前の状態ということであり、Stage 1というのは大雑把に言えばTC39（JavaScript (ECMAScript) の標準化を担当する技術委員会）がその問題領域にやっと興味を持ったという段階です。つまり、JavaScriptの標準ライブラリは**まだ仕様の完成には程遠く、実用可能になるまであと何年かかってもおかしくないような状態**です。いますぐ実用できるものではないという点は理解しておきましょう。

- [JavaScript Standard Library Proposal](https://github.com/tc39/proposal-javascript-standard-library)

なお、このプロポーザルでは「標準ライブラリという仕組み」を導入することを議論しているのであり,
「どんなモジュールが標準ライブラリとして今後JavaScriptに組み込まれるのか」はまた別の問題であるということに留意してください。

このプロポーザルを主導しているのは、（例によって）Googleの面々です。これはまだ初期段階のプロポーザルですがGoogleはこのプロポーザルの推進に非常に積極的であり、後で紹介しますがGoogle Chromeはすでに実験的な標準ライブラリの実装を持っています。

## 標準ライブラリの意義

では、なぜJavaScriptに標準ライブラリが必要なのでしょうか。それは、**JavaScriptの機能拡大を促進するため**です[^cite_extensible_library]。JavaScriptの言語仕様はそこそこ複雑ですが、それは構文や文法という面に重きが置かれている傾向にあります。プログラムを書きやすくするための便利な関数が揃っているかとか、そういう観点ではまだJavaScriptの言語機能は豊富とは言えないでしょう。その結果として、[lodash](https://www.npmjs.com/package/lodash)のような便利モジュールが人気を得ています。それの何が問題かといえば、lodashが多くのサイトで使われるということはlodashのソースコードが大量にインターネット回線の上を日々飛び交っているということになります。JavaScriptの機能が拡張されてlodashが不要になればこのトラフィックは削減できるのです。

[^cite_extensible_library]: “[The goal of this proposal is to define a mechanism for enabling a more extensive standard library in JavaScript than is currently available.](https://github.com/tc39/proposal-javascript-standard-library/blob/242b1b317270a5a5242f212addb59208f5fe695f/README.md)”

また、少し上で説明したように、従来JavaScriptに組み込みの言語機能は主に**グローバル変数**を用いて提供されてきました。そうなると、新機能を追加したい場合には新しいグローバル変数を増やすことになります。例えば、最近ではES2017の共有メモリに関する機能追加で`SharedArrayBuffer`と`Atomics`というグローバル変数が追加されました。

この方式では、既存のコードの動作に影響が出るかもしれない、すなわち**後方互換性が失われるかもしれない**という問題があります。例えばJavaScriptは最近`global`というグローバル変数を追加しようとしましたが、それだと後方互換性が壊れてしまうことが判明したので`globalThis`という名前に変更になりました。（これについては[筆者の別の記事](https://qiita.com/uhyo/items/f3b6feef9444e86bef94)で解説していますのでぜひご覧ください。）

JavaScriptは後方互換性を重視する言語ですから、それが壊れる心配がある状態ではJavaScriptへの機能追加の速度が低下します。実際、上記の`global`は後方互換性が壊れた騒動のおかげで標準化が当初より数年くらい遅れています。

この問題は、追加機能をグローバルに追加するのではなく新しいモジュールとして実装してそこから`import`する方式にすることで回避できます。追加された新モジュールを既存コードが`import`していることはありえないためです[^dynamic_import]。

[^dynamic_import]: 正確に言えば、ダイナミック`import()`を用いて標準ライブラリを読み込もうとするコードがもし事前にあった場合には動作に影響を与える可能性がありますが、その場合は明らかに標準ライブラリの存在を意識していますし、自己責任と言えるでしょう。

また、グローバル変数が増えるとJavaScript実行コンテキストの初期化のコストが増しますので、それを回避できるのも利点となります。モジュールとして機能が用意されていれば、オーバーヘッドはそれが`import`されたときしか発生しません[^std_pros_overhead]。

[^std_pros_overhead]: “[they won't add any overhead to starting up a new JavaScript runtime context (e.g. a new tab, worker, or service worker), and they won't consume any memory or CPU unless they're actually imported.](https://developers.google.com/web/updates/2019/03/kv-storage)”

## 標準ライブラリの具体例

すでに説明されているように、標準ライブラリはまだ標準化の途上にある仕様です。しかし、早速標準ライブラリに追加されるべきモジュールが議論されています。

### [KV Storage](https://github.com/WICG/kv-storage)

**KV Storage**は、ブラウザ向けの新しいKey-valueストアです。イメージとしては`localStorage`がモダンになってリメイクされた感じです。もちろんこれも中身が確定していない提案段階の仕様ですが、記事執筆時点で既にGoogle Chromeに実験的な実装が搭載されており、実際に試すことができます。これは**[the Web's First Built-in Module](https://developers.google.com/web/updates/2019/03/kv-storage)**と銘打って宣伝されていることからも分かる通り、標準ライブラリのモジュールとして提供されています。使い方については[Googleの紹介記事](https://developers.google.com/web/updates/2019/03/kv-storage)や[それを日本語に直したQiita記事](https://qiita.com/okumurakengo/items/34299d2fb454a1316910)がありますのでそちらを参照してください。1行だけ引用しますが、以下のように`std:kv-storage`モジュールから機能をインポートできます。

```js
import {storage, StorageArea} from 'std:kv-storage';
```

個人的にはプレフィクスは`js:`のはずだったのにこれは`std:`な点とかが多少気になりますが、前者についてはそもそもプレフィックスが安定していないことが原因なのでそのうち直るかもしれない[^js_and_std]と思っています。

[^js_and_std]: KV Storageのページにも、`std:`の部分は変わるかもしれないという註釈があります。

このKV Storageは、この記事に書いてあることの中で唯一**今すぐ試せる機能**です。試してみるにはGoogle Chromeのexperimentalフラグをオンにする必要があります（詳しくは上記のリンク先を参照してください）が、興味がある方は試してみるのもよいでしょう。

### [Accessing the originals](https://github.com/domenic/get-originals)

これは新しくてまだTC39プロセスに乗ってすらいないただのアイデアですが、グローバル変数として提供されてきた従来の言語機能もモジュールとして標準ライブラリに載せようという提案です。

この提案の背景には、**そもそもグローバル変数で提供されるAPIが信用できない場合がある**という問題があります。JavaScriptの初期の仕様は処理系から提供されるオブジェクトも自由に書き換え可能なゆるいものであり、JavaScriptは後方互換性を保つために現在までそのゆるさを引きずっています。それゆえ、処理系により提供されているAPIが書き換えられている可能性があるのです。

例えば、`Array.isArray`は与えられたオブジェクトが配列かどうかを調べる組み込み機能です。

```js
/** 与えられたオブジェクトが配列なら要素を追加する関数 */
function addToArr(obj) {
  if (Array.isArray(obj)) {
    obj.push(123);
  }
}

addToArr([1, 2, 3]);    // pushされる
addToArr({foo: "bar"}); // 何も起きない
```

ここで定義した`addToArr`関数はif文で`obj`が配列かどうか調べることで、`obj.push`でエラーが発生するのを防いでいます。特に問題のあるコードには見えません。

ところが、このコードは次のようにするとエラーが発生してしまいます。

```js
/** 与えられたオブジェクトが配列なら要素を追加する関数 */
function addToArr(obj) {
  if (Array.isArray(obj)) {
    obj.push(123);
  }
}

// Array.isArrayを書き換える！！！！！！
Array.isArray = ()=> true;

addToArr([1, 2, 3]);    // pushされる
addToArr({foo: "bar"}); // ここでエラーが発生
```

このコードでは`Array.isArray`が常に`true`を返すように変更してしまうことで、`addToArr`を壊しています。このことから分かるように、`addToArr`が正しいといえるのは`Array.isArray`が書き換えられていないという保証があるときだけなのです。

この例のように`addToArr`の定義のすぐ下で`Array.isArray`を書き換える馬鹿はいないと思いますが、`Array`がグローバル変数であるということは全く関係ない別のところで`Array`が書き換えられている可能性があるわけで、`addToArr`がエラーを起こさないことを確信するのがたいへん難しくなっています。

今回の提案“accessing the originals”を使うと、このコードは次のように書き換えられます。

```js
import { isArray_static } from "std:global/Array";

function addToArray(obj) {
  if (isArray_static(obj)) {
    obj.push(123);
  }
}
```

どう変わったかというと、`std:global/Array`という組み込みモジュールから`isArray_static`関数を読み込んでそれを`Array.isArray`の代わりに使用しています。ざっくり言えば、`std:global/Array`は`Array`というグローバル変数が持つ機能を提供するものであり、`Array`が持つプロパティである`isArray`が`isArray_static`という名前でエクスポートされています。この`isArray_static`は仕様で定義された`Array.isArray`そのものであり、外的要因によって書き換えられていないことが保証されています。これにより、`Array.isArray`が想定通りの動作をしない可能性があるという問題を解決しています。

ここで、十分賢い読者の方は上記のコードにまだ懸念点があることにお気づきになったでしょう。それは、`Array.prototype.push`が書き換えられているかもしれないという問題です。上記のコードは次のように攻撃されると想定通りの動作をしません。

```js
import { isArray_static } from "std:global/Array";

function addToArray(obj) {
  if (isArray_static(obj)) {
    obj.push(123);
  }
}

// Array.prototype.pushを消してしまう
Array.prototype.push = null;

addToArray([1, 2, 3]); // エラーが発生
```

これに対する解決策は、もちろん`Array.prototype.push`も標準ライブラリから取得することです。実は、`Array.prototype.push`の本来の中身は`push`として`std:global/Array`からエクスポートされています。よって、以下のようにすればよいでしょう。

```js
import { isArray_static, push } from "std:global/Array";

function addToArray(obj) {
  if (isArray_static(obj)) {
    push.call(obj, 123);
  }
}

// Array.prototype.pushを消してしまう
Array.prototype.push = null;

addToArray([1, 2, 3]); // OK!
```

`push`はメソッドとして使わなければいけないので`this`が`obj`になるようにしなければいけません。そのために`call`メソッドを使っています。

では、これで`addToArray`は完璧ですね。

……と言いたいところですが、実はそうではありませんね。勘の良い読者の方はお分かりの通り、`Function.prototype.call`が書き換えられていたら`push.call`が失敗する可能性があります。ということで、`Function.prototype.call`も標準ライブラリからインポートしましょう。

```js
import { isArray_static, push } from "std:global/Array";
import { call } from "std:global/Function";

function addToArray(obj) {
  if (isArray_static(obj)) {
    call.call(push, obj, 123);
  }
}
```

`push.call(obj, 123)`を`call`を用いて書き換えるには、`call`の`this`が`push`である必要があります。よって、`call.call(push, obj, 123);`というようにこれを呼び出す必要がありますね。

ここで、**いやちょっと待てよ**と思わなかった方は思慮が不足しています。`call.call`は`Function.prototype.call`なのでこれでは問題が解決していません。`Function.prototype.call`が汚染されているという不安を解消するために`Function.prototype.call`を使用するという本末転倒の状態になっています[^function_prototype_apply]。

[^function_prototype_apply]: 一応補足すると、`Function.prototype.apply`を使う手もありますが、こちらも一緒に書き換えられる可能性があり大して意味はありません。

幸いにして、ES2015では`Function.prototype.call`への依存を回避する手段である[Reflect.apply](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply)が追加されました。これを代わりに使えば解決です。今回のサンプルの最終形は次のとおりです。

```js
import { isArray_static, push } from "std:global/Array";
import { apply } from "std:global/Reflect";

function addToArray(obj) {
  if (isArray_static(obj)) {
    apply(push, obj, [123]);
  }
}
```

このサンプルでは、組み込みの機能は全て標準ライブラリから取得しています。よって、外部で何がどう書き換えられていようとこのプログラムは影響を受けません。これは非常に堅牢なプログラムであると言えます。このように、`std:global`以下のモジュールを標準ライブラリに追加するこの提案によって、外的要因によって壊れないプログラムを書くことができるのです。

しかし、これは元々のプログラムに比べて随分**回りくどい**というか**物々しい**感じがします。こうまでしないと安全性を担保できないJavaScriptという言語にそもそも問題があるのではと言われると反論できません。しかし、需要は確かにありそうな感じがします。

ここでお伝えしたいことは、とにかく標準ライブラリにはこのような使い道もあるということです。**モジュールからインポート**という形を取ることで、目的の機能が外的要因によって（グローバル変数を介することによって）書き換えられるのを防いでいます。

## Polyfillはどうするのか

標準ライブラリが導入された後に問題となると考えるのは、**Polyfill**をどのように作って利用していくかということです。標準ライブラリに含まれるモジュールが今後追加されていくとしても、実行環境によってその実装時期には差がでるでしょう。例えば`js:temporal`モジュールが追加されたとしても、未対応のブラウザは以下のコードに対してエラーを発生させるでしょう。

```js
import { CivilDate } from "js:temporal";
```

これに対処するためには「知らないモジュール名が指定されていたら代わりにPolyfillを読み込む」というメカニズムが必要になります。

現状では、これに対処するための複数の提案がありますのでこれを紹介します。背景には[Layered API](https://blog.jxck.io/entries/2018-05-01/layered-apis.html)というものがありますがここではこれには深入りしません。

### Layered APIs fallback syntax

この[提案](https://docs.google.com/document/d/1jRQjQP8DmV7RL75u_67ps3SB1sjfa1bFZmbCMfJCvrM/edit)では、以下のような記法でフォールバック先を指定可能にするという案があります（リンク先を読めば分かる通りあくまで候補の一つですが）。

```js
import { storage } from
       "std:kv-storage|https://some-cdn.com/kv-storage.js";
```

ポイントは、`|`で`std:kv-storage`と`https://some-cdn.com/kv-storage.js`の2つのモジュール名を区切っている点です。この記法は、前者を読み込んでみて無理だったら後者を読み込むという意味になります。これにより、`std:kv-storage`をまだ知らないブラウザは後者のURLを読み込んでPolyfillを適用できるというわけです（この場合、`|`記法にそもそも対応していないブラウザでは動作しないという問題点がありますが）。

### import maps

Web標準の方面からも別の[提案](https://github.com/WICG/import-maps)が出ています。これは前述のKV Storageと一緒にすでにChromeで実験的に実装されています。

import mapsは、HTMLファイル中で以下のように指定します。

```html
<script type="importmap">
{
  "imports": {
    "std:kv-storage": [
      "std:kv-storage",
      "https://some-cdn.com/kv-storage.js"
    ]
  }
}
</script>
```

`type="importmap"`という特別な`type`属性を持ったscript要素がimport mapとして機能します。中身はJSONです。見れば何となくわかる通り、import mapはモジュール名を別のモジュール名やURLに読み替えさせる機能を持ちます。上のimoort mapは`"std:kv-storage"`というモジュール名が指定されたらまず`std:kv-storage`というモジュールを試し、だめだったら`/node_modules/kvs-polyfill/index.mjs`というモジュールを試すという意味になります。前述の`|`記法とやっていることは同じですね。

こちらの方法は肝心の`import`文が`import from "std:kv-storage";`のままでいいという利点がありますが、Webプラットフォームでしか通用しないという欠点があります。そもそもimport mapsを知らないブラウザにとっては意味がないという点はそんなに変わりませんね[^import_maps_key]。

[^import_maps_key]: import mapsの場合はPolyfillのURLをキーとして先に標準の`std:kv-storage`を読み込むようなimport mapsを書いておいて使う側はPolyfillのURLを`import`で読むようにしておくことで、import mapsを知らないブラウザは普通にPolyfillを読み込んで、import mapsを知っていてかつPolyfillが必要ないブラウザは組み込みのものを使うようにすることも可能です。このあたりのことを自動的にやってくれる次世代のバンドラ（？）を作ったら受けるんじゃないかという気もします。調べていないので既にあるかもしれませんが。

## 標準ライブラリの`import`方法の他の候補

上で説明した通り、標準ライブラリをインポートするには次のように`js:`プレフィックスを持ったモジュール名を`import`文で指定します。

```js
import { CivilDate } from "js:temporal";
```

これが一番支持を得ているようですが、他の候補も[以前に議論されており](https://github.com/tc39/ecma262/issues/395)、完全に確定しているわけではありません。`std:`と`js:`もこの議論で両方姿を現しています。

いずれにせよ、重要なことは従来の（ユーザー定義の）モジュールとは区別できる必要があるという点です。

### `import`元を文字列以外にする案

これは、以下のように`from`の右を文字列以外にすることで構文レベルで別物にするという案です。

```js
imoort { CivilDate } from std.temporal;
```

`std`というグローバル変数がありそうな感じに見えるのが微妙です[^import_source_std_global]。

[^import_source_std_global]: “[The downside of using std.________ is that it start to look like a global object that is also available in other contexts.](https://github.com/tc39/proposal-javascript-standard-library/)”

また、以下のような案もあります。

```js
import { CivilDate } from <temporal>;
```

### npmのscoped package を流用する案

以下のように、モジュール名の前に`@std/`などをつける案です。

```js
import { CivilDate } from "@std/temporal";
```

これは代替案の中では比較的人気がある案ですが、標準ライブラリとその他のモジュールを区別できるかどうかという点において一段劣っています（一応`@std`については大丈夫なようです）。一方で、Polyfillが比較的容易であるという強みがあります。

### URLにする案

```js
import { CivilDate } from "https://www.ecma-international.com/ecmascript/temporal";
```

長くて覚えられないですが、公式がPolyfillを提供したりするのが楽かもしれません（node.jsが少しつらそうですが）。

## まとめ

この記事ではJavaScriptにおける**標準ライブラリ**の概念を説明しました。標準ライブラリは仕様に含まれているモジュール群であり、`import`するときは`js:`（あるいは`std:`）で始まるモジュール名を使うのが特徴です。標準ライブラリの概念により後方互換性の心配なく言語機能を追加できるようになるのに加え、機能追加によるオーバーヘッドの対策にもなります。

`js:`と`std:`でプレフィックスが揺れているなどまだまだ不安定なこの提案ですが、いずれJavaScriptやWebの新機能は（文法的なものを除いて）標準モジュールを介して提供される未来が来ると考えられます。ぜひその時に備えておきましょう。