目的
-
標準仕様における定型的な記述の重複を排除します。
-
標準仕様間の規約・用語・データ構造の統一を図ります。
-
複数の標準仕様で用いられるが適切な場所がない概念の受け皿となります。
-
曖昧になりがちな概念を明確にし、分かりやすく読みやすいアルゴリズム記述の助けとなります。
追加の目的についての提案も歓迎します。
1. 利用方法
この標準をXというタイトルの文書で利用するには、以下のように記述します。
X は インフラ に依存する。 [Infra]
また、曖昧さを避けるため、すべての用語の相互参照を強く推奨します。
2. 規約
2.1. 適合性
すべてのアサーション、図、例、および注記は非規範的であり、明示的に非規範的と記載されたセクションも同様です。それ以外はすべて規範的です。
キーワード "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", "OPTIONAL" は RFC 2119 で記載されている通りに解釈されます。 [RFC2119]
これらのキーワードは小文字で書かれても同等の意味を持ち、非規範的な内容には使用できません。
これは、読みやすさやRFC 8174以前の多くの文書における長年の慣習を考慮した結果、意図的な違反としてRFC 8174に反していることに注意してください。 [RFC8174]
上記の内容は本標準だけでなく、本標準を利用する文書にも適用されます。本標準を利用する文書では "must", "must not", "should", "may" に限定し、小文字で用いることがより読みやすいと一般に考えられるため推奨します。
非規範的な内容では "strongly encouraged", "strongly discouraged", "encouraged", "discouraged", "can", "cannot", "could", "could not", "might", "might not" を代わりに用いることができます。
2.2. 他の仕様への準拠
一般に、仕様はさまざまな他の仕様と連携し依存しています。しかし残念ながら、要件が衝突し、他の仕様の要件に違反する必要が生じる場合があります。このような場合、インフラ現行標準を利用する文書では、その逸脱を意図的な違反として明記し、理由も記載してください。
前のセクション § 2.1 適合性 では 意図的な違反(RFC 8174に対するもの)がインフラによって記載されています。
2.3. 用語
「または(or)」という語は、包摂的(両方も可)の場合(例:「幅または高さが0の場合」)は「両方も含む」の意味であり、排他的な場合は明示的に「両方は不可」と記されます。
ユーザーエージェントとは、ユーザーの代わりに動作するソフトウェアエンティティであり、たとえばウェブコンテンツの取得・表示や、エンドユーザーとのやりとりの仲介などを行います。インフラ現行標準を利用する仕様では、ユーザーエージェントは一般に仕様を実装したクライアントソフトウェアのインスタンスです。このクライアントソフトウェア自体を実装と呼びます。 一人のユーザーが複数のユーザーエージェントを使い分けることもあり、たとえば実装を複数プロファイルやプライベートブラウジングモードで同時に動作させる場合も含まれます。
何かが実装依存とされている場合、その詳細は実装依存の対象となる実装に委ねられます。そうした記載がない場合は逆に、本標準を利用するドキュメントでは実装は定められたルールに従わなければなりません。
input に U+000A (LF) コードポイントを挿入する際、各行が最大 width コードポイントとなるよう、実装依存の方法で処理します。この要件における「行」は input の開始、終了、および U+000A (LF) で区切られます。
2.4. プライバシーに関する懸念
インフラ現行標準を利用する文書で定義される一部の機能は、ユーザーの利便性と引き換えに、ある程度のプライバシーを犠牲にする場合があります。
一般的に、インターネットの構造上、ユーザーはIPアドレスによって識別されます。しかし、ユーザーがデバイスやネットワークを移動するとIPアドレスも変わり、逆にNATやプロキシ、共有PCにより、一つのIPアドレスから複数のユーザーのアクセスが発生する場合もあります。また、オニオンルーティング等の技術でリクエストの発信元を匿名化し、一つのユーザーのリクエストがネットワーク上の様々な場所から発信されているように見せることも可能です。[RFC791]
しかし、ユーザーのリクエストを結び付ける手段はIPアドレスだけではありません。たとえばCookieはまさにこの目的で設計されており、ウェブのセッション機能の多くはこれを基盤としています(アカウントでのログインなど)。より広くは、キャッシュや共有状態(HSTS、HTTPキャッシュ、コネクションのグルーピング、ストレージAPIなど)も悪用されうることを想定すべきです。[COOKIES] [RFC6797] [STORAGE]
さらに微妙な手法もあります。ユーザーのシステム固有の特徴を収集し、十分な情報が集まれば、個々のユーザーのブラウザの「デジタルフィンガープリント」を計算できます。これはIPアドレス以上に、同じユーザーからのリクエストを特定できる場合があります。
このようなリクエストのグルーピングは、特に複数サイト間で悪意のある目的に利用される恐れがあります。たとえば、ある人が経路検索した住所(自宅住所)と、参加しているフォーラムサイトから推測される政治的傾向を突き合わせて、その人の選挙での投票を妨害するなどです。
このような悪用が極めて深刻になり得るため、ユーザーエージェントの実装者や仕様策定者は、指紋付けや追跡に使われうる情報の漏洩を最小限に抑えるよう強く推奨します。
しかし、冒頭でも述べた通り、指紋付けや追跡に悪用されうるAPIの公開は大きな利便性をもたらす場合もあり、全ての情報漏洩を防ぐだけでは十分とは言えません。たとえば、特定のIDでサイトにログインして投稿するには、同一ユーザーからのリクエストであることを識別できる必要があります。さらに、キャンバス上でテキストに枠を描画するなど、テキストの幅を取得する機能も、フォント情報の推定によるユーザーのグルーピングにつながる可能性があります。
インフラ現行標準を利用する文書で定義される機能のうち、トラッキングベクトルとして利用され得るものは、この段落のように明示されます。
同様の目的で利用されうる他のプラットフォーム機能には、次のようなものがあります。
- ユーザーエージェントがサポートする機能の正確なリスト
- スクリプトにおける再帰の最大許可スタック深度
- ユーザー環境を記述する機能
- ユーザーのタイムゾーン
- HTTPリクエストヘッダ
3. アルゴリズム
3.1. 適合性
アルゴリズムや、アルゴリズムの一部として命令形で記述された要件(例:「先頭の空白を除去する」「falseを返す」など)は、そのアルゴリズムや手順の導入部で用いられているキーワード(例:"must")の意味で解釈されます。キーワードがない場合は "must" が暗黙的に適用されます。
例えば、仕様で次のように記載されていたとします:
オレンジを食べるには、ユーザーは次を行う:
- オレンジの皮をむく。
- オレンジを一房ずつ分ける。
- オレンジの房を食べる。
これは次の記述と同等です:
オレンジを食べるには:
- ユーザーはオレンジの皮をむかなければならない。
- ユーザーはオレンジを一房ずつ分けなければならない。
- ユーザーはオレンジの房を食べなければならない。
ここでのキーワードは "must" です。
上記の例を修正して、アルゴリズムの導入部が単に "To eat an orange:" であっても、"must" が暗黙的に適用されるため、意味は同じです。
アルゴリズムや個別の手順として記述された適合要件は、最終的な結果が同等である限り、どのような方法で実装しても構いません(特に、アルゴリズムは理解しやすいことを目的としており、性能を意図したものではありません)。
性能はユーザーの体感やコンピュータアーキテクチャ、入力の種類など、さまざまな要因に左右されるため取り扱いが難しいものです。例えば、JavaScriptエンジンは標準化された単一のアルゴリズムに対して複数の実装経路を持ち、速度やメモリ消費の最適化を図っています。すべての実装経路を標準化するのは現実的でなく、長期的な観点からも単一のアルゴリズムを標準化する方が望ましいため、性能面は各実装間の競争分野に委ねられます。
3.2. アルゴリズム入力の制限回避
インフラ現行標準を利用する文書では、アルゴリズムの入力に関して、そのサイズやリソース使用量などに明確な制限を設けないことが一般的です。これによりユーザーエージェント間の競争を促し、将来の計算需要も妨げません。
ただし、ユーザーエージェントは、他に制限がない場合でも
実装依存の制限を課すことができます。例えば、サービス拒否攻撃を防ぐため、メモリ不足を防ぐため、またはプラットフォーム固有の制約を回避するためなどです。
グローバルなリソース制限は、リソース枯渇攻撃の一形態として副次的なチャネルとなり得ます。攻撃者が被害者のアプリケーションがグローバル制限に達したかを観測できるためです。また、制限がユーザーエージェント固有の場合は、フィンガープリントの手段ともなり得ます(基盤となるハードウェア固有の場合など)。
メモリ上にビットマップを作成できるAPIは、任意の大きさ、またはJavaScriptの
Number.MAX_SAFE_INTEGER
のような大きな上限まで許可すると仕様できるかもしれません。しかし、実装では巨大なメモリ割当てを避けるために、実装依存(つまり仕様としては未規定)の上限を設けても構いません。
あるプログラミング言語で最大コールスタックサイズが仕様として定められていない場合でも、実装では実用上の理由から上限を設けても構いません。
コードが特定の制限に依存する場合もあり、相互運用性のために上限を定義することが有用な場合もあります。将来的にも問題がなければ、それを受け入れることで、より多くのユーザーエージェントでコードが動作するようになります。
また、実装依存の上限に下限を設け、すべての実装が一定の最小サイズの入力を扱えるようにすることも有用です。
3.3. 宣言
アルゴリズム名は通常動詞句ですが、標準や読者がより慣用的に参照できるよう、その存在自体を強調する名前が付けられる場合もあります。
後者の例としては、「属性変更手順」「内部モジュールスクリプトグラフ取得手順」「オーバーロード解決アルゴリズム」などがあります。
アルゴリズムは、次の形式で名前・パラメーター・戻り値の型を宣言します:
[アルゴリズム名]するには、[型1] [parameter1]、[型2] [parameter2] … を与えて、次の手順を実行する。戻り値は[戻り値の型]である。
(動詞句でないアルゴリズム名では「[アルゴリズム名]を実行するには…」とします。より複雑なパラメーター宣言形式については§ 3.4 パラメーターも参照してください。)
バイト列 bytes を与えて 素晴らしいフォーマットをパースするには、次の手順を実行する。戻り値は 文字列 または null である。
値を返さないアルゴリズムでは、より短い形式を用います。返り値が手順から明らかな場合もこの短縮形を用いて構いません:
[アルゴリズム名]するには、[型1] [parameter1]、[型2] [parameter2] … を与えて:
バイト列 bytes を与えて 素晴らしいフォーマットをパースするには:
非常に短いアルゴリズムは、1文で宣言・記述できます:
バイト列 bytes を与えて 素晴らしいフォーマットをパースするには、bytesの等価デコードをASCII大文字化した結果を返す。
型はアルゴリズム宣言に含めるべきですが、パラメーター名が十分に明確な場合や文脈から明らかな場合は省略できます(たとえば、単に他のアルゴリズムのラッパーである場合など)。
クラシックスクリプトを読み込むには、urlを与えて、内部スクリプト読み込みアルゴリズムをurlと"classic
"で実行した結果を返す。
3.4. パラメーター
アルゴリズムのパラメーターは通常、§ 3.3 宣言で説明したように順番に列挙されます。ただし、より複雑な場合もあります。
パラメーターはオプションにでき、その場合は宣言で明記し、必須パラメーターの後に記載します。デフォルト値を与える場合と、アルゴリズム本体で値が与えられたかどうかを判定する場合があります。具体的な記法は以下の通りです:
… オプションの[型] [parameter] …
… オプションの[型] [parameter](既定値 [default value])…
オプションのbooleanパラメーターは必ずデフォルト値を指定し、その値はfalseでなければなりません。
navigateを実行するには、リソースresource、オプションの文字列navigationType、オプションのboolean exceptionsEnabled(既定値false)を与えて:
- …
- navigationType が与えられていれば、それを使って何かを行う。
- …
このようなオプションの位置引数パラメーターを持つアルゴリズムを呼び出す際は、末尾のオプションの引数のみ省略できます。
上記アルゴリズムの呼び出し例:
- navigate to resource。
- navigate to resource with
"
form submission
"。 - navigate to resource with
"
form submission
" and true。
ただし、2番目の引数を省略して3番目に非デフォルト値を与えることはできません。また、最後の呼び出し例では "true" が「例外有効」であることが分かりづらく、宣言まで戻ってパラメーターを数える必要があります。これを解決する方法は後述します。
位置引数でなく名前付き引数を使うことで、呼び出し時の明確さと柔軟性が向上します。こうしたパラメーターは変数と定義の両方としてマークアップし、呼び出し元からリンクします。
navigateを実行するには、リソースresource、オプションの文字列navigationType、オプションのboolean exceptionsEnabled(既定値false)を与えて:
- …
- navigationType が与えられていれば、それを使って何かを行う。
- …
呼び出し例は下記のようになります:
- navigate to resource。
- navigate to resource with navigationType set to
"
form-submission
"。 - navigate to resource with exceptionsEnabled set to true。
- navigate to resource with navigationType set to
"
form-submission
" and exceptionsEnabled set to true。
アルゴリズム手順内では、引数値はパラメーター宣言へのリンクではなく、単なる変数参照として記載されます。パラメーター宣言へのリンクは呼び出し箇所でのみ行います。
必須の名前付きパラメーターも同様に、変数と定義の両方としてマークアップし、呼び出し元からリンクします。これにより呼び出し時の明確さが向上します。
Boolean型パラメーターは必須・オプションに関わらず名前付きにすることで呼び出し時の明確さが大きく向上します。詳しくはThe Pitfalls of Boolean Trapもご参照ください。
明確さを高める補完的な手法として、関連する値群を構造体にまとめてパラメーターとして渡すことも有効です。特に同じ値群を複数のアルゴリズムで入力として使う場合に適しています。
3.5. 変数
変数は "let" で宣言し、"set" で変更します。
list を新しい リストとする。
isActivationEvent が true で target がアクティベーション動作を持つ場合は target、そうでなければ null を activationTarget とする。
変数は宣言前に使用してはなりません。変数は ブロックスコープ です。1つのアルゴリズム内で同じ変数を複数回宣言してはなりません。
複数代入構文を使うと、カンマで区切った変数名を括弧で囲み、タプルの 要素 に複数の変数を同時に割り当てられます。割り当てる変数の数は タプルの 要素の数と一致しなければなりません。
-
statusInstance を status (200, `
OK
`) とする。 -
(status, statusMessage) を statusInstance とする。
status と statusMessage への代入は、インデックスまたは名前でタプルの要素にアクセスして2段階で書くこともできます。
3.6. 制御フロー
アルゴリズムの制御フローは、「return」や「throw」要求によって、そのステートメントが属するアルゴリズムを終了させます。「return」は与えられた値(ある場合)を呼び出し元に返します。「throw」は、与えられた値(ある場合)で例外を発生させ、呼び出し元のアルゴリズムも自動的に例外を再スローして終了します。本文で明示すれば、呼び出し元は例外を「catch」して別の処理を実行できます。
3.7. 条件付き中断
ある条件が成立したときに手順の実行を中断したい場合があります。
その場合、特定の条件に達したらその手順を中断する(abort when)と記述します。これは、指定された手順のそれぞれの前に条件を評価し、真なら残りの手順をスキップするステップを挿入して評価することを示します。
このようなアルゴリズムでは、続く手順に「中断時(if aborted)」と注記でき、その場合は直前の中断条件が真になってスキップされた場合に必ず実行されます。
この構文を使う場合、実装は手順の実行中に条件を評価しても、各手順の前後で評価しても、最終的な結果が区別できなければどちらでも構いません。例えば、上記例で result が計算中に変更されなければ、ユーザーエージェントは計算を途中で停止できます。
3.8. 条件文
条件文を持つアルゴリズムでは "if"、"then"、"otherwise" キーワードを使うべきです。
-
value を null とする。
-
input が 文字列 であれば、value に input を設定する。
-
value を返す。
一度 "otherwise" キーワードが使われたら、"then" は省略します。
-
value を null とする。
-
input が 文字列 であれば、value に input を設定する。
-
それ以外の場合、value を failure に設定する。
-
value を返す。
3.9. 反復
条件に達するまで一連の手順を繰り返す方法はいくつかあります。
インフラ現行標準はこれについて(まだ)網羅的ではありません。必要な場合はissueを提出してください。
反復の流れは、continue や break 要求で制御できます。 continue は反復内の残りの手順をスキップして次の項目に進みます。次の項目がなければ反復は終了します。break は残りの手順と項目の両方をスキップし、反復を終了します。
example を リスト « 1, 2, 3, 4 » とする。次の記述は operation を1, 2, 3, 4 の順に実行します:
-
For each item of example:
- item に対して operation を実行する。
次の記述は operation を1, 2, 4 に実行し、3はスキップされます。
次の記述は operation を1, 2 に実行し、3と4はスキップされます。
3.10. アサーション
可読性を高めるために、アルゴリズムにアサーション(不変条件の明示)を追加することが有用な場合があります。その場合は「アサート:」に続けて、常に成り立つべき文を記述します。この文が偽になった場合は、インフラ現行標準を利用する文書に問題があることを意味し、報告・対応されるべきです。
アサーションは常に真でなければならないため、実装に影響はありません。
-
x を "
Aperture Science
" とする。 -
アサート:x は "
Aperture Science
" である。
4. プリミティブデータ型
4.1. Null
null値は値が存在しないことを示すために用いられます。これはJavaScriptのnull値と相互に扱うことができます。[ECMA-262]
4.2. Boolean
Booleanは true または false のいずれかです。
4.3. 数値
数値は複雑です。詳細は issue #87 を参照してください。将来的には型や数学演算についてのガイダンスも追加したいと考えています。ご協力歓迎します!
8ビット符号なし整数は、0から255(0〜28 − 1)までの整数です(両端含む)。
16ビット符号なし整数は、0から65535(0〜216 − 1)までの整数です(両端含む)。
32ビット符号なし整数は、0から4294967295(0〜232 − 1)までの整数です(両端含む)。
64ビット符号なし整数は、0から18446744073709551615(0〜264 − 1)までの整数です(両端含む)。
128ビット符号なし整数は、0から340282366920938463463374607431768211455(0〜2128 − 1)までの整数です(両端含む)。
IPv6アドレスは128ビット符号なし整数です。
8ビット符号付き整数は、−128から127(−27〜27−1)までの整数です(両端含む)。
16ビット符号付き整数は、−32768から32767(−215〜215−1)までの整数です(両端含む)。
32ビット符号付き整数は、−2147483648から2147483647(−231〜231−1)までの整数です(両端含む)。
64ビット符号付き整数は、−9223372036854775808から9223372036854775807(−263〜263−1)までの整数です(両端含む)。
4.4. バイト
バイトは8ビットの並びであり、"0x
"に2つのASCII大文字16進数字を続けて表記します。値の範囲は0x00〜0xFFです。バイトの値はその内部の数値です。
ASCIIバイトは、0x00(NUL)から0x7F(DEL)までのバイトです。0x28, 0x29 以外のASCIIバイトは、ASCII format for Network Interchangeの Standard Code セクションで定められた表記(括弧内)で続けて示すことができます。[RFC20]
0x28 の場合「(left parenthesis)」、0x29 の場合「(right parenthesis)」と続けます。
0x49 (I) を UTF-8デコードすると、符号位置 U+0049 (I) になります。
4.5. バイト列
バイト列はバイトの並びであり、バイトをスペースで区切って表現します。0x20(SP)〜0x7E(~)のバイトのみで構成される場合は、文字列としても表せますがダブルクォートではなくバッククォートで囲みます(文字列型との混同を避けるため)。
文字列からバイト列に変換するには、EncodingのUTF-8エンコードの使用が推奨されます。まれに等価エンコードが必要な場合もあります。[ENCODING]
バイト列をバイト小文字化するには、含まれるバイトのうち 0x41(A)〜0x5A(Z)の範囲のものを0x20だけ加算します。
バイト列をバイト大文字化するには、含まれるバイトのうち 0x61(a)〜0x7A(z)の範囲のものを0x20だけ減算します。
バイト列 A が、バイト大文字小文字非区別で一致するのは、バイト小文字化した A が バイト小文字化した B と一致する場合です。
バイト列 potentialPrefix が、接頭辞であるかどうかは、以下の手順で true になる場合です:
-
i を 0 とする。
-
While true:
"input で始まる potentialPrefix" は "potentialPrefix が input の接頭辞である" と同義です。
バイト列 a が バイト小なりで バイト列 b となるのは、以下の手順で true になる場合です:
-
b が 接頭辞であれば false を返す。
-
a が 接頭辞であれば true を返す。
-
n を、a の n 番目のバイトと b の n 番目のバイトが異なる最小のインデックスとする(どちらも接頭辞でないので必ず存在する)。
-
a の n 番目のバイトが b の n 番目のバイトより小さければ true を返す。
-
false を返す。
4.6. 符号位置
符号位置はUnicodeの符号位置であり、"U+"に4〜6桁のASCII大文字16進数字を続けて表記します。値の範囲はU+0000〜U+10FFFFです。符号位置の値は内部の数値です。
符号位置の直後には、その名前、またはU+0028やU+0029以外の場合はレンダリング結果(括弧書き)、またはその両方を続けてもよいです。インフラ現行標準を利用する文書では、レンダリングできない場合やU+0028/U+0029の場合は名前を、そうでなければ判読性のためレンダリング結果(括弧書き)を続けることが推奨されます。
符号位置の名前はUnicodeで定義されており、ASCII大文字で表現されます。[UNICODE]
🤔としてレンダリングされる符号位置はU+1F914で表されます。
この符号位置を参照する場合、「U+1F914 (🤔)」と表記して文脈を補足できます。さらに「U+1F914 THINKING FACE (🤔)」と書いても構いませんが、やや冗長です。
U+000Aのように明確にレンダリングしにくい符号位置は「U+000A LF」と表せます。U+0029はレンダリングできるものの括弧の対応を避けるため「U+0029 RIGHT PARENTHESIS」と表せます。
符号位置は文脈によって文字と呼ばれることもあり、"0x"で始めて表記される場合もあります。
前方サロゲートは、U+D800〜U+DBFFの範囲にある符号位置です。
後方サロゲートは、U+DC00〜U+DFFFの範囲にある符号位置です。
非文字は、U+FDD0〜U+FDEF(両端含む)、またはU+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, U+10FFFF のいずれかに該当する符号位置です。
ASCII符号位置は、U+0000(NULL)〜U+007F(DELETE)の範囲の符号位置です。
ASCIIタブまたは改行は、U+0009(TAB)、U+000A(LF)、U+000D(CR)です。
ASCII空白は、U+0009(TAB)、U+000A(LF)、U+000C(FF)、U+000D(CR)、U+0020(SPACE)です。
"Whitespace"(空白)は不可算名詞です。
XML、JSON、およびHTTP仕様の一部ではU+000C(FF)を空白として扱いません:
新しい機能には、XML/JSON/HTTP専用でない限りインフラ現行標準のASCII空白定義の使用を推奨します。
C0制御文字は、U+0000(NULL)〜U+001F(INFORMATION SEPARATOR ONE)の範囲の符号位置です。
C0制御文字またはスペースは、C0制御文字またはU+0020(SPACE)です。
制御文字は、C0制御文字またはU+007F(DELETE)〜U+009F(APPLICATION PROGRAM COMMAND)の範囲の符号位置です。
ASCII数字は、U+0030(0)〜U+0039(9)の範囲の符号位置です。
ASCII大文字16進数字は、ASCII数字またはU+0041(A)〜U+0046(F)の範囲の符号位置です。
ASCII小文字16進数字は、ASCII数字またはU+0061(a)〜U+0066(f)の範囲の符号位置です。
ASCII16進数字は、ASCII大文字16進数字またはASCII小文字16進数字です。
ASCII大文字アルファベットは、U+0041(A)〜U+005A(Z)の範囲の符号位置です。
ASCII小文字アルファベットは、U+0061(a)〜U+007A(z)の範囲の符号位置です。
ASCIIアルファベットは、ASCII大文字アルファベットまたはASCII小文字アルファベットです。
ASCII英数字は、ASCII数字またはASCIIアルファベットです。
4.7. 文字列
文字列は16ビット符号なし整数(コード単位とも呼ばれる)の並びです。文字列はJavaScript文字列とも呼ばれます。 文字列はダブルクォートと等幅フォントで表記します。
これはUnicodeでの「コード単位」の定義とは異なります。特に、Unicode 16ビット文字列の定義に限定されます。[UNICODE]
文字列は、JavaScript仕様のThe String Typeセクションで定義される変換により、符号位置を含むものとして解釈できます。[ECMA-262]
この変換処理ではサロゲートペアが対応するスカラ値に変換され、残るサロゲートは元の符号位置に対応付けられ、実質的にそのまま残ります。
0xD83D, 0xDCA9, 0xD800 のコード単位で構成される文字列は、符号位置として解釈すると U+1F4A9 と U+D800 からなります。
文字列が含む符号位置に追加の制約がある場合、この仕様ではASCII文字列、等価文字列、スカラ値文字列を定義します。これらを使うことで仕様の明確性が増します。
ASCII文字列は、その符号位置がすべてASCII符号位置である文字列です。
等価文字列は、その符号位置がU+0000(NULL)〜U+00FF(ÿ)の範囲にある文字列です。
スカラ値文字列は、その符号位置がすべてスカラ値である文字列です。
スカラ値文字列はI/OやUTF-8エンコードが関わるあらゆる操作に便利です。
変換により文字列をスカラ値文字列にするには、サロゲートをU+FFFD (�) に置換します。
置換されるサロゲートはサロゲートペアの一部ではありません。文字列を符号位置として解釈する過程で、サロゲートペアはすでにスカラ値に変換されるためです。
スカラ値文字列は常に文字列として暗黙的に使えます(すべてのスカラ値文字列は文字列だからです)。逆に、文字列はサロゲートを含まないことが分かっている場合のみスカラ値文字列として暗黙的に使えます。そうでなければ変換が必要です。
実装によっては文字列やスカラ値文字列の表現方法によって明示的な変換が必要な場合もあります。多くの実装ではパフォーマンスやメモリの理由で文字列だけでも複数の実装が存在するのが一般的です。
文字列 a が 等しい(is) または同一である 文字列 b とは、同じ順序のコード単位からなる場合です。
特に断りがない限り、すべての文字列比較は等しい(is)比較を用います。
この文字列の比較は、HTML における従来の「大文字小文字を区別する」比較と同じです。等しい文字列同士は大文字小文字の違いだけでなく、正規化形式や結合記号の順序など、符号位置のエンコーディングの差異にも敏感です。Unicodeで視覚的または正規等価とされる2つの文字列でも、等しいとは限りません。[HTML] [UNICODE]
文字列 potentialPrefix がコード単位接頭辞として文字列 input の先頭にあるかどうかは、以下の手順でtrueとなります:
-
i を 0 とする。
-
While true:
どちらかの文字列が U+0020(SPACE)〜U+007E(~)のみを含むリテラルであるなど、文脈からコード単位による比較であることが明らかな場合、「input で始まる potentialPrefix」は「potentialPrefix が input のコード単位接頭辞である」と同義として使えます。
値が不明な場合は明示的に記述した方がよい例:targetString は コード単位接頭辞で
userInput です。一方、リテラルの場合は簡潔に「userInput で始まる \"!
\"」のように書けます。
文字列 potentialSuffix がコード単位接尾辞として文字列 input の末尾にあるかどうかは、以下の手順でtrueとなります:
-
i を 1 とする。
-
While true:
-
potentialSuffixIndex を potentialSuffix の長さ−iとする。
-
inputIndex を input の長さ−iとする。
-
potentialSuffixIndex が0未満なら true を返す。
-
inputIndex が0未満なら false を返す。
-
potentialSuffixCodeUnit を potentialSuffixIndex番目のコード単位とする。
-
inputCodeUnit を inputIndex番目のコード単位とする。
-
potentialSuffixCodeUnit が inputCodeUnit でなければ false を返す。
-
i に i + 1 を設定する。
-
どちらかの文字列が U+0020(SPACE)〜U+007E(~)のみを含むリテラルであるなど、文脈からコード単位による比較であることが明らかな場合、「input で終わる potentialSuffix」は「potentialSuffix が input のコード単位接尾辞である」と同義として使えます。
値が不明な場合は明示的に記述した方がよい例:targetString は コード単位接尾辞で
domain です。一方、リテラルの場合は簡潔に「domain で終わる \".
\"」のように書けます。
文字列 a がコード単位小なりで 文字列 b となるのは、以下の手順で true になる場合です:
-
b が コード単位接頭辞で a なら false を返す。
-
a が コード単位接頭辞で b なら true を返す。
-
n を、a の n 番目のコード単位と b の n 番目のコード単位が異なる最小のインデックスとする(どちらも接頭辞でないので必ず存在する)。
-
a の n 番目のコード単位が b の n 番目のコード単位より小さければ true を返す。
-
false を返す。
これはJavaScriptの<
演算子や、配列のsort()
メソッドで用いられている順序と一致します。この順序は各文字列の16ビットコード単位を比較し、非常に効率的・一貫性・決定論的なソート順を生み出します。結果的に、サロゲートペアで表現される符号位置も含め、特定のアルファベットや辞書順とは一致しません。[ECMA-262]
たとえば、U+FF5E(全角チルダ, ~)はU+1F600(😀)より明らかに小さいですが、チルダは単一コード単位0xFF5Eで、スマイリーは2つのコード単位0xD83D, 0XDE00で構成されるため、スマイリーはコード単位小なりでチルダとなります。
コード単位部分文字列は、文字列 string の start から長さ length で切り出した部分文字列を以下の手順で求めます:
-
アサート:start と length は0以上である。
-
result を空文字列とする。
-
start から start + length まで(exclusive)の範囲の各 i について:string の i 番目のコード単位を result に追加する。
-
result を返す。
コード単位部分文字列は、文字列 string の start から end までの部分を、start から長さ end − start のコード単位部分文字列として切り出します。
コード単位部分文字列は、文字列 string の start から末尾までを、コード単位部分文字列(start から string の長さまで)として切り出します。
"Hello world
" の コード単位部分文字列(開始1・長さ3)は
"ell
" です。これは 1から4のコード単位部分文字列とも表現されます。
これらのアルゴリズムで使われる数値は、コード単位そのもののインデックスではなく、その「間」の位置と考えるのがよいです。返される部分文字列は、その区間に挟まれたコード単位で構成されます。例えば、空文字列における 0から0のコード単位部分文字列が空文字列になる理由です。
符号位置部分文字列は、文字列 string の start から長さ length で切り出した部分文字列を以下の手順で求めます:
-
アサート:start と length は0以上である。
-
result を空文字列とする。
-
start から start + length まで(exclusive)の範囲の各 i について:string の i 番目の符号位置を result に追加する。
-
result を返す。
符号位置部分文字列は、文字列 string の start から end までを、start から長さ end − start の符号位置部分文字列として切り出します。
符号位置部分文字列は、文字列 string の start から末尾までを、符号位置部分文字列(start から string の符号位置長まで)として切り出します。
一般に、開発者が指定する位置や長さが与えられている場合はコード単位部分文字列を使います。これはJavaScriptの文字列インデックスの動作に合わせたものです。たとえばCharacterData
クラスのメソッドなど。[DOM]
それ以外の場合、符号位置部分文字列のほうがよいでしょう。たとえば、"👽
" の0から長さ1の符号位置部分文字列は
"👽
" ですが、コード単位部分文字列ならサロゲートU+D83Bだけの文字列になります。
ASCII小文字化は、文字列中のすべてのASCII大文字アルファベットを対応するASCII小文字アルファベットの符号位置に置換します。
ASCII大文字化は、文字列中のすべてのASCII小文字アルファベットを対応するASCII大文字アルファベットの符号位置に置換します。
文字列 A が ASCII大文字小文字非区別で 文字列 B と一致するとは、A のASCII小文字化がBのASCII小文字化と等しい場合です。
ASCIIエンコードは、ASCII文字列 input に対して、等価エンコードした結果を返します。
等価エンコードとUTF-8エンコードは、この入力に対して同じバイト列を返します。
改行除去は、文字列から U+000A(LF)と U+000D(CR)の符号位置を取り除きます。
改行正規化は、文字列中の U+000D(CR) U+000A(LF)のペアをすべて単一の U+000A(LF)に置き換え、残る U+000D(CR)もすべて U+000A(LF)に置換します。
先頭と末尾のASCII空白除去は、文字列の先頭・末尾にあるASCII空白をすべて取り除きます。
ASCII空白除去・折り畳みは、文字列中の1個以上連続するASCII空白の並びを単一のU+0020(SPACE)に置換し、その後先頭と末尾のASCII空白も除去します。
符号位置の列を収集するには、ある条件conditionを満たすものを 文字列 inputから収集し、位置変数 positionがinput内で呼び出しアルゴリズムの位置を追跡するものとする:
-
result を空の文字列とする。
-
position がinputの末尾を越えておらず、かつ position 位置の符号位置が条件 condition を満たす間:
-
その符号位置をresultの末尾に追加する。
-
position を1進める。
-
-
result を返す。
このアルゴリズムは収集した符号位置を返すだけでなく、呼び出しアルゴリズム内の位置変数も更新します。
ASCII空白をスキップするには、文字列 inputと位置変数 positionが与えられたとき、 ASCII空白である符号位置を inputからpositionを使って収集する。収集された符号位置自体は使わないが、 positionは更新される。
厳密分割は、文字列 input を区切り文字符号位置 delimiter で分割する際、次を行います:
-
positionをinput用の位置変数とし、最初はinputの先頭を指すようにする。
-
tokenを、positionを使い、inputからdelimiterと等しくない 符号位置の列を収集するの結果とする。
-
positionがinputの末尾を越えていない間、次を繰り返す:
-
positionを1進める。
-
tokenを、positionを使い、inputからdelimiterと等しくない 符号位置の列を収集するの結果とする。
-
tokensを返す。
このアルゴリズムは「厳密な」分割であり、以下のASCII空白用・カンマ用分割(どちらも間にASCII空白がある場合など様々な緩和あり)と対照的です。
ASCII空白で分割は、文字列 input について次を行います:
-
positionをinput用の位置変数とし、最初はinputの先頭を指すようにする。
-
input内でpositionを使い、ASCII空白をスキップする。
-
positionがinputの末尾を越えていない間、次を繰り返す:
-
tokenを、positionを使い、inputからASCII空白でない 符号位置の列を収集するの結果とする。
-
input内でpositionを使い、ASCII空白をスキップする。
-
-
tokensを返す。
-
position をinput用の位置変数(初期値は先頭)とする。
-
positionがinputの末尾を越えない限り:
-
tokenを、positionを使い、inputからU+002C(,)でない 符号位置の列を収集するの結果とする。
tokenは空文字列の場合もある。
- tokenの先頭と末尾のASCII空白を除去する。
-
もしpositionがinputの末尾を越えていなければ:
-
-
tokensを返す。
連結は、リスト list(要素型:文字列)について、オプションの区切り文字列 separator を使って次を実行します:
集合 set を直列化するには、U+0020(SPACE)で区切って連結したものを返す。
4.8. 時間
時間は moment(瞬間) 型および duration(期間) 型で表現します。これらを定義したりJavaScriptとやりとりしたりする際は、High Resolution Time § 3 仕様策定者のためのツールの助言に従ってください。[HR-TIME]
5. データ構造
従来、仕様ではさまざまな曖昧な仕様レベルのデータ構造を、意味の共有認識をもとに扱ってきました。これは一般的にうまく機能しますが、たとえば反復順序や、すでに順序付き集合に含まれるitemをappendした場合など、端のケースで曖昧さが生じることがあります。また、特に複雑なデータ構造(mapなど)については記法や表現が分かれがちでした。
本標準は、共通の基盤を作るために、共通のデータ構造とそれを扱うための記法や表現を少数提供します。
5.1. リスト
リストは、有限個の順序付き 項目から成る仕様上の型である。
記法上の便宜として、リストを«»で囲み、itemをカンマで区切ってリテラル表記できます。添字アクセスは角括弧内に0始まりのインデックスを指定します。添字は、existsと併用する場合を除き、範囲外にしてはなりません。
example を リスト « "a
", "b
", "c
", "a
" »
とすると、example[1] は 文字列
"b
" です。
記法上の便宜として、複数代入構文を使ってリストのitemを複数の変数に同時に割り当てても構いません。割り当てる変数を«»で囲み、カンマで区切ります。リストのsizeと変数の個数は同じでなければなりません。各変数にはリストの同じインデックスのitemが割り当てられます。
リストの内容が完全に制御されていない場合(たとえばユーザー入力由来のリストなど)、複数代入構文を使う前にリストのsizeが期待通りかどうかを確認すべきです。
-
list のsizeが
3
でなければ failure を返す。 -
« a, b, c » を list とする。
append は 順序付き集合でないリストの末尾にitemを追加することです。
拡張 は、順序付きセットでないリスト Aを、リスト Bで拡張するには、B の各 itemに対し、item を A に追加する。
prepend は 順序付き集合でないリストの先頭にitemを追加することです。
replace は 順序付き集合でないリスト中の、指定条件に一致するitemをすべて、そのitemで置き換える(該当なしなら何もしない)ことです。
上記の定義は、リストが順序付き集合の場合は修正されます。下記の ordered set append、prepend、replace を参照してください。
insert は リスト内で指定インデックスの直前(インデックス0なら先頭)にitemを挿入することです。
remove は リストから指定条件に一致するitemをすべて除去する(該当なしなら何もしない)ことです。
xをリスト « x, y, z, x » から除去すると、xに等しいitemすべてが除去され、リストは « y, z » となります。
"a"で始まるitemをすべてリスト «
"a
", "b
", "ab
", "ba
" » から除去すると、"a"と"ab"が除かれ、リストは «
"b
", "ba
" » となります。
empty は リストのitemをすべてremoveすることです。
リストがitemを含むとは、そのitemがリスト中に存在することです。リスト list とインデックス index について、「list[index] exists」とも表せます。
インデックス取得は、リストのインデックスとして 0 からsize(exclusive)までの範囲を返します。
iterateは、リストの各itemに順に一連の手順を行う際、「For each item of list」の形で記述します。以降の本文でitemに対し処理します。
clone は リスト list と同じdesignationの新しいリスト cloneを作成し、for each item of list で appendして、同じ順序・内容のリストを作ります。
これは「浅いclone」です。item自身は複製しません。
originalを順序付きセット «
"a
", "b
", "c
" » とする。originalを複製すると、
新しい順序付きセット
cloneが作られる。clone内の
"a
" を
"foo
" に置換すると « "foo
", "b
", "c
"
» となるが、
original[0] は依然として文字列
"a
" のままである。
昇順ソートは、リスト list・less thanアルゴリズム lessThanAlgo で、list と同じitemを持つ新リスト sorted を生成し、lessThanAlgo に従って各itemが後続のitemより小さい順になるように並べます。同順位(両方向false)のitemは元の順番を維持します。
降順ソートは、昇順ソートの逆順です。lessThanAlgoで後続itemより小さいitemが前に来るように並べ、新リスト sorted を作ります。同順位は元の順序を維持します。
original
を リスト « (200, "OK
"), (404,
"Not Found
"), (null, "OK
") » とし、2番目のitemがコード単位小なりとなる順で昇順ソートすると、結果は « (404,
"Not Found
"), (200, "OK
"), (null, "OK
") » となります。
リスト型はJavaScript仕様(大文字のList)由来であり、その定義要素の一部をここに再掲し、さらにリスト操作用の語彙を拡張しています。JavaScriptがListを要求する場合、本標準のリストが使えます(同じ型です)。[ECMA-262]
5.1.1. スタック
一部のリストはスタックと指定されます。スタックもリストですが、通常はappend、prepend、removeではなく、以下の操作を使います。
popは、スタックが空でなければ、末尾のitemをremoveして返します。空なら何も返しません。
peekは、スタックが空でなければ、末尾のitemを返します。空なら何も返しません。
スタックもリストですが、for eachは使わず、whileとpopの組み合わせが適切です。
5.1.2. キュー
一部のリストはキューと指定されます。キューもリストですが、通常はappend、prepend、removeではなく、以下の操作を使います。
dequeueは、キューが空でなければ、先頭のitemをremoveして返します。空なら何も返しません。
キューもリストですが、for eachは使わず、whileとdequeueの組み合わせが適切です。
5.1.3. 集合
一部のリストは順序付き集合と指定されます。順序付き集合は、同じitemを2回含まないという意味が追加されたリストです。
ウェブプラットフォームのほとんどのケースでは、順序を持つ集合が必要です。なぜなら、開発者に見せる列挙の順序がブラウザ間で一貫していなければならないからです。順序が重要でない場合でも順序付き集合を使い、実装では順序が観測されないことを利用して最適化できます。
集合生成は、リスト input を与えて次を行います:
appendは、順序付き集合に指定itemがすでに含まれていれば何もしません。含まれていなければ通常のリストのappend操作を行います。
拡張 は、順序付きセット Aを リスト Bで拡張するには、B の各 itemに対し、item を A に追加する。
prependは、順序付き集合に指定itemがすでに含まれていれば何もしません。含まれていなければ通常のリストのprepend操作を行います。
replaceは、順序付き集合 set において、itemまたはreplacementが含まれていれば最初のものをreplacementで置き換え、それ以外の重複をremoveします。
"a"を"c"にreplaceする場合、順序付き集合 « "a", "b", "c" » は « "c", "b" » となります。« "c", "b", "a" » も « "c", "b" » となります。
順序付き集合 set が別の順序付き集合 supersetの部分集合(supersetは上位集合)であるとは、for each item of set について、supersetがitemを含む場合です。
これは、順序付きセットは自分自身の部分集合かつ 上位集合であることを意味する。
集合 A が 等しい(equal) 集合 B なのは、A が部分集合かつ上位集合である場合です。
交差(intersection)は、順序付き集合 A, B について、新しい順序付き集合 set を生成し、for each item of A について、B が item を含んでいれば append します。
和集合(union)は、順序付き集合 A, B について、Aをcloneしたsetに、for each item of B で appendします。
差(difference)は、順序付き集合 A, B について、新しい順序付き集合 set を生成し、for each item of A について、B が item を含まなければ append します。
範囲(the range) n to m(inclusive)は、nからmまで(両端含む)の整数を昇順で含む新しい順序付き集合を生成します(m ≥ nの場合)。
範囲(exclusive) n to m は、nからm−1まで(両端含まず)の整数を昇順で含む新しい順序付き集合を生成します(m > nの場合)。m=nなら空集合となります。
For each n of 範囲 1 to 4, inclusive, …
5.2. マップ
順序付きマップ(時には単に「マップ」とも呼ばれる)は、 有限個のタプルからなる順序付き列で構成される仕様型であり、各タプルは キーと 値からなり、 同じキーが二度現れることはありません。このような各タプルは エントリーと呼ばれます。
順序付きセットと同様に、現行標準では実装間の相互運用性のため、 マップには順序性が必要であると仮定します。
リテラル構文を使って順序付きマップを示すことができ、 マップ全体を«[ ]»で囲み、各エントリーをkey → valueの形で記述し、 エントリー同士はカンマで区切ります。
exampleを順序付きマップ
«[
"a
" → `x
`, "b
" → `y
` ]»とする。
このときexample["a
"]はバイト列 `x
`である。
エントリーの値を取得するには、 順序付きマップ mapと キー key、および任意の defaultを与える:
また、インデックス記法を使って値の取得を示すこともできる。 これは、マップの直後に角括弧で キーを指定する。 デフォルト値を与えたい場合は、with defaultの後に デフォルト値を記載する。
map["test
"]
が存在する場合は、
map["test
"]を返す。
exampleを順序付きマップ
«[ "a
" → "x
", "b
" → "y
" ]»とする。
このときexample["a
"]は
example["a
"] with default
"z
"と同じ、すなわち"x
"となる。
example["c
"]はアサートに失敗する。
example["c
"] with default "z
"は"z
"となる。
エントリーの値を設定するには、 順序付きマップ内で既存の エントリーが 指定キーを持つ場合はその値を更新し、 そうでなければ新たなエントリーをマップの末尾に追加することを意味します。 また、順序付きマップ map、キーkey、値valueについて 「set map[key] to value」と記述することもできる。
エントリーを削除するには、 順序付きマップから 条件に一致するエントリーをすべて削除し、 該当しない場合は何もしません。 条件が特定のキーの場合は、 順序付きマップ mapとキーkeyについて 「remove map[key]」と記述できる。
クリアするとは、 順序付きマップの 全エントリーを削除することです。
順序付きマップは 指定キーを持つエントリーを含む とは、そのキーを持つエントリーが存在することを意味します。 順序付きマップ mapとキーkeyに対して 「map[key] exists」とも記述できます。
キーを取得するには、 順序付きマップ内の エントリーの各 キーを アイテムとする 新しい順序付きセットを返します。
値を取得するには、 順序付きマップ内の エントリーの各 値を アイテムとする 新しいリストを返します。
順序付きマップの サイズは、 そのマップに対してキーを取得した結果の サイズです。
順序付きマップは 空であるとは、 サイズが0である場合をいう。
反復するには、 順序付きマップ内の各エントリーに 順に一連の手順を適用する。例えば 「For each key → value of map」と記述し、その後の文章でkeyとvalueに操作を行う。
複製するには、 順序付きマップ mapから 新しい順序付きマップ cloneを作成し、 各 key → valueについて clone[key]に valueを設定します。
originalを順序付きマップ
«[
"a
" → «1, 2, 3», "b
" → «» ]»とする。
複製したoriginalは
新しい順序付きマップ
cloneとなるので、
clone["a
"]に
«-1, -2, -3»を設定しても
«[ "a
" → «-1, -2, -3», "b
" → «» ]»となりoriginalは変更されない。
しかしclone["b
"]に4を追加すると、
cloneとoriginal両方で
対応する値が変更される。これは両方が
同じリストを指しているため。
昇順ソートは、 マップ mapと 比較アルゴリズムlessThanAlgoを使って 新しいマップ sortedを作成し、 そのエントリーをlessThanAlgoの基準で、 各エントリーが後続のエントリーより小さい順に並べる。比較結果が同じ(両方向でfalse)場合は、 sorted内での順序はmapの順序を維持する。
降順ソートは、 マップ mapと 比較アルゴリズムlessThanAlgoを使って 新しいマップ sortedを作成し、 そのエントリーをlessThanAlgoの基準で 各エントリーが前のエントリーより小さい順に並べる。比較結果が同じ(両方向でfalse)場合は、 sorted内での順序はmapの順序を維持する。
5.3. 構造体
構造体とは、 有限個の 項目から構成される仕様型であり、それぞれの項目は一意かつ不変な 名前を持ちます。項目は定義された型の値を保持します。
emailは、構造体の例であり、 local part(文字列)とhost(ホスト)から構成されます。
架空のアルゴリズムは次のようにこの定義を利用できます:
- emailを、local partが"
hostmaster
"でhostがinfra.example
のemailとする。 - …
5.3.1. タプル
タプルとは、 構造体の一種で、その項目が順序付けられているものです。 記法上の利便性のため、タプルは括弧で囲み、項目をカンマで区切るリテラル構文で表現できます。 この記法を使うには名前が文脈から明らかである必要があります。 そのためには最初の出現時にタプルに名前を与えておきます。 インデックス記法として、タプルに対して0始まりの添字を角括弧で指定できます。 添字は範囲外であってはなりません。
statusは、タプルの例であり、 code(数値)とtext(バイト列)からなります。
タプルstatusを操作する架空のアルゴリズム例:
- statusInstanceをstatus (200, `
OK
`)とする。 - statusInstanceを(301, `
FOO BAR
`)に設定する。 - もしstatusInstanceのcodeが404なら…
最後の手順は「もしstatusInstance[0]が404なら…」と書くこともできます。 タプルの名前に明示的な定義がない場合、この書き方の方が好ましいかもしれません。
すべての構造体がタプルであるとは限らないのは意図的です。 Infra Standardを利用する文書は、依存先で使われているリテラル構文を壊さずに自身の構造体に新しい名前を追加できる柔軟性を必要とすることがあります。 その場合、タプルは適切ではありません。
6. JSON
この節のアルゴリズムで用いられる規約は、JavaScript仕様のものです。[ECMA-262]
JSON文字列をJavaScript値にパースするには、 文字列 stringが与えられたとき:
-
次を返す:? Call(%JSON.parse%, undefined, « string »)。
JSONバイト列をJavaScript値にパースするには、 バイト列 bytesが与えられたとき:
-
stringを、UTF-8デコードを bytesに対して実行した結果とする。[ENCODING]
-
JSON文字列をJavaScript値にパースするを stringに対して実行した結果を返す。
JavaScript値をJSON文字列に直列化するには、 JavaScript値valueが与えられたとき:
-
resultを ? Call(%JSON.stringify%, undefined, « value ») の結果とする。
%JSON.stringify%に追加の引数は渡されていないため、 生成される文字列には空白が挿入されません。
-
もしresultがundefinedなら、
TypeError
を投げる。これはvalueがJSON表現を持たない場合(例えば、undefinedや関数の場合)に発生します。
-
resultを返す。
JavaScript値をJSONバイト列に直列化するには、 JavaScript値valueが与えられたとき:
-
stringをJavaScript値をJSON文字列に直列化するを valueに対して実行した結果とする。
-
UTF-8エンコードを stringに対して実行した結果を返す。[ENCODING]
上記の操作はJavaScript値に直接作用します。特に、ここで扱うオブジェクトや配列は特定のJavaScriptレルムに結び付けられます。現行標準では、JSONとレルム非依存なマップ、 リスト、文字列、真偽値、数値、null間の変換がしばしば便利です。
JSON文字列をInfra値にパースするには、 文字列 stringが与えられたとき:
-
jsValueを ? Call(%JSON.parse%, undefined, « string »)の結果とする。
-
JSON由来のJavaScript値をInfra値に変換するを jsValueに対して実行した結果を返す。
JSONバイト列をInfra値にパースするには、バイト列 bytesが与えられたとき:
-
stringをUTF-8デコードを bytesに対して実行した結果とする。[ENCODING]
-
JSON文字列をInfra値にパースするを stringに対して実行した結果を返す。
JSON由来のJavaScript値をInfra値に変換するには、JavaScript値 jsValueが与えられたとき:
-
もしIsArray(jsValue)がtrueなら:
-
resultを空の順序付きマップとする。
-
各 keyについて! jsValue.[[OwnPropertyKeys]]()を反復:
-
jsValueAtKeyを! Get(jsValue, key)とする。
-
infraValueAtKeyをJSON由来のJavaScript値をInfra値に変換するを jsValueAtKeyに対して実行した結果とする。
-
-
resultを返す。
Infra値をJSON文字列に直列化するには、 文字列、 真偽値、数値、null、リスト、または 文字列キーのマップ valueが与えられたとき:
-
jsValueを Infra値をJSON互換のJavaScript値に変換するを valueに対して実行した結果とする。
-
! Call(%JSON.stringify%, undefined, « jsValue ») の結果を返す。
%JSON.stringify%に追加の引数は渡されていないため、 生成される文字列には空白が挿入されません。
Infra値をJSONバイト列に直列化するには、文字列、 真偽値、数値、null、リスト、または 文字列キーのマップ valueが与えられたとき:
-
stringをInfra値をJSON文字列に直列化するを valueに対して実行した結果とする。
-
UTF-8エンコードを stringに対して実行した結果を返す。[ENCODING]
Infra値をJSON互換のJavaScript値に変換するには、valueが与えられたとき:
-
もしvalueがリストなら:
-
jsValueを! ArrayCreate(0)とする。
-
iを0とする。
-
各 listItemについて、valueを反復:
-
listItemJSValueを Infra値をJSON互換のJavaScript値に変換するを listItemに対して実行した結果とする。
-
! CreateDataPropertyOrThrow(jsValue, ! ToString(i), listItemJSValue)を実行する。
-
iにi + 1を設定する。
-
-
jsValueを返す。
-
-
アサート:valueはマップである。
-
jsValueを! OrdinaryObjectCreate(null)とする。
-
各 mapKey → mapValueについて、valueを反復:
-
アサート:mapKeyは文字列である。
-
mapValueJSValueを Infra値をJSON互換のJavaScript値に変換するを mapValueに対して実行した結果とする。
-
! CreateDataPropertyOrThrow(jsValue, mapKey, mapValueJSValue)を実行する。
-
-
jsValueを返す。
仕様中でJavaScript値を直接操作することはほとんど適切ではないため、原則として Infra値をJSON文字列に直列化する または Infra値をJSONバイト列に直列化する を用いるべきです。もしInfra値をJSON互換のJavaScript値に変換するの使用が必要だと思われる場合は、 Issueを作成してユースケースをご相談ください。
7. 許容的base64
許容的base64エンコードは、バイト列 dataが与えられたとき、RFC 4648のセクション4で定義されたbase64アルゴリズムをdataに適用し、その結果を返す。 [RFC4648]
これは許容的base64エンコードと名付けられているが、これは 許容的base64デコードとの対称性のためであり、後者はRFCと異なり 特定の入力に対するエラー処理を定義している。
許容的base64デコードは、文字列dataが与えられたとき、次の手順を実行する:
-
dataからすべてのASCII空白を除去する。
-
もしdataの符号位置長が4で割り切れるなら:
-
もしdataが1個または2個のU+003D(=) 符号位置で終わっていれば、それらをdataから除去する。
-
-
もしdataの符号位置長を4で割った余りが1なら、失敗を返す。
-
もしdataが次のいずれでもない符号位置を含んでいれば:
- U+002B (+)
- U+002F (/)
- ASCII英数字
失敗を返す。
-
outputを空のバイト列とする。
-
bufferを、ビットを追加できる空のバッファとする。
-
positionを、dataの位置変数として、最初はdataの先頭を指すようにする。
-
positionがdataの末尾を越えない間、繰り返す:
-
もしbufferが空でなければ、12ビットまたは18ビットが入っている。 12ビットの場合は最後の4ビットを捨て、残り8ビットを8ビットビッグエンディアン数値とする。 18ビットの場合は最後の2ビットを捨て、残り16ビットを2つの8ビットビッグエンディアン数値とする。 その1つまたは2つの値をバイトとして順にoutputに追加する。
捨てられるビットにより、例えば"
YQ
"や"YR
"のどちらも`a
`を返す。 -
outputを返す。
8. 名前空間
HTML名前空間は
"http://www.w3.org/1999/xhtml
" である。
MathML名前空間は
"http://www.w3.org/1998/Math/MathML
" である。
SVG名前空間は
"http://www.w3.org/2000/svg
" である。
XLink名前空間は
"http://www.w3.org/1999/xlink
" である。
XML名前空間は
"http://www.w3.org/XML/1998/namespace
" である。
XMLNS名前空間は
"http://www.w3.org/2000/xmlns/
" である。
謝辞
次の方々に多大な感謝を捧げます: Addison Phillips, Andreu Botella, Aryeh Gregor, Ben Kelly, Chris Rebert, Daniel Ehrenberg, Dominic Farolino, Gabriel Pivovarov, Ian Hickson, Jakob Ackermann, Jake Archibald, Jeff Hodges, Jeffrey Yasskin, Jungkee Song, Leonid Vasilyev, Maciej Stachowiak, Malika Aubakirova, Martin Thomson, Michael™ Smith, Mike West, Mike Taylor, Ms2ger, Pavel "Al Arz" Kurochkin, Philip Jägenstedt, Rashaun "Snuggs" Stovall, Sergey Shekyan, Simon Pieters, Tab Atkins, Tobie Langel, triple-underscore, Wolf Lammen, およびXue Fuqiao に心より敬意を表します!
本標準は Anne van Kesteren (Apple, annevk@annevk.nl) と Domenic Denicola (Google, d@domenic.me) によって執筆されています。
知的財産権
Copyright © WHATWG (Apple, Google, Mozilla, Microsoft)。本作業は Creative Commons Attribution 4.0 International License の下でライセンスされています。その一部がソースコードに組み込まれている場合、ソースコード内の該当部分は BSD 3-Clause License の下でライセンスされます。
これは現行標準です。 特許レビュー版に関心がある方は 現行標準レビュー草案をご覧ください。