term タグ別の記事一覧

ECMAScript 2015(ES6)でのクラス定義におけるclassキーワードとfunctionキーワードの違い

 ECMAScript 2015では、新たにクラスを定義するためのclassキーワードが導入されている。MDNで提供されているドキュメントの「Classes」ページでは、「ECMAScript 6 で導入されたクラス構文は、既存のプロトタイプによるオブジェクト指向の糖衣構文です」と記述されている。しかし、厳密にチェックするとclassキーワードで定義したクラスとfunctionキーワードで定義したクラスは(実用上問題ないレベルで)挙動が微妙に異なる。その違いを検証してみよう。なお、検証に使用した環境はNode.js v6.2.1である。

$ node -v
v6.2.1

宣言方法の違い

 functionキーワードを使ってクラスを定義する場合、次のようにコンストラクタとしてクラス名を持つ関数を定義するのが一般的だ。

> function VectorFunction(x, y) {
... this.x = x;
... this.y = y;
... }
undefined

 いっぽうclassキーワードを利用する場合、次のようにconstructor関数を使ってクラスのコンストラクタを定義する。

> class VectorClass {
... constructor(x, y) {
..... this.x = x;
..... this.y = y;
..... }
... }
[Function: VectorClass]

 classキーワードを利用した場合でも、作成されるのはあくまでFunctionオブジェクト(=関数)である。

newキーワードなしで実行した際の挙動の違い

 これらのクラスのインスタンスを作成するには、この関数をnewキーワード付きで実行する。

> v1 = new VectorFunction(3, 4)
VectorFunction { x: 3, y: 4 }
> v2 = new VectorClass(3, 4)
VectorClass { x: 3, y: 4 }

 この挙動はどちらの場合も同じだ。しかし、newキーワード無しでクラスを関数として実行した場合、functionキーワードを使って定義したクラスとclassキーワードを使って定義したクラスは挙動が異なる。

 functionキーワードを使って定義したクラスは、newキーワード無しで関数として実行すると意図しない結果を生み出すことがある。なぜなら、newキーワード無しで関数を実行した場合、this変数にglobalオブジェクト(strict modeの場合はundefined)が渡されるからだ。

 たとえば今回のケースでは、非strict modeの場合グローバルオブジェクトのプロパティが勝手に変更されてしまう。

> x = 0
0
> y = 0
0
> v1 = VectorFunction(3, 4)
undefined
> x
3
> y
4

 いっぽう、classキーワードで定義したクラスはそのまま実行することはできず、TypeErrorが発生する。

> v2 = VectorClass(3, 4)
TypeError: Class constructor VectorClass cannot be invoked without 'new'
    at repl:1:6
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:224:10)
    at REPLServer.Interface._line (readline.js:566:8)
    at REPLServer.Interface._ttyWrite (readline.js:843:14)

 ECMA-262の「14.5.14 Runtime Semantics: ClassDefinitionEvaluation」および「9.2.9 MakeClassConstructor(F)」で説明されているが、classキーワードでクラスを定義した場合、生成されたFunctionオブジェクトの「FunctionKind」内部スロットに「classConstructor」という値がセットされる。この内部スロットはFunctionオブジェクトの種別を格納するもので、「normal」および「classConstructor」、「generator」のいずれかを持つ(「9.2 ECMAScript Function Objects」)。FunctionKind内部スロットの値がclassConstructorの場合、関数を実行する際に実行される「Call」内部メソッドの実行時にTypeError例外が送出される(「9.2.1 [[Call]] ( thisArgument, argumentsList)」)。なお、FunctionKind内部スロットの値がclassConstructorになるのは、classキーワードでクラスを定義した場合のみである。

所有するプロパティの違い

 classキーワードで定義したクラスは、functionキーワードで定義したクラスと異なり「caller」および「arguments」プロパティを持たない。

> Object.getOwnPropertyNames(VectorFunction)
[ 'length', 'name', 'arguments', 'caller', 'prototype' ]
> Object.getOwnPropertyNames(VectorClass)
[ 'length', 'name', 'prototype' ]

 また、classキーワードで定義したクラスのprototypeプロパティはwritableではないが、functionキーワードで定義したクラスのprototypeプロパティはwritableである。

> Object.getOwnPropertyDescriptor(VectorFunction, "prototype")
{ value: VectorFunction {},
  writable: true,
  enumerable: false,
  configurable: false }
> Object.getOwnPropertyDescriptor(VectorClass, "prototype")
{ value: VectorClass {},
  writable: false,
  enumerable: false,
  configurable: false }

 もちろん、どちらの場合もprototypeオブジェクトにプロパティ/メソッドを追加することは可能だ。

> VectorFunction.prototype.norm = function () {
... return Math.sqrt(this.x * this.x + this.y * this.y);
... }
[Function]
> VectorClass.prototype.norm = function () {
... return Math.sqrt(this.x * this.x + this.y * this.y);
... }
[Function]

 このようにして定義したメソッドは、どちらも同じように実行することが可能だ。

> v1 = new VectorFunction(3, 4)
VectorFunction { x: 3, y: 4 }
> v1.norm()
5
> v2 = new VectorClass(3, 4)
VectorClass { x: 3, y: 4 }
> v2.norm()
5

functionキーワードを使ったクラス宣言でしかできないこと

 classキーワードを使ってクラスを宣言すると、そのクラス自体を関数として実行することができなくなる。多くの場合でこのこと自体にデメリットはないが、意図的に(newキーワードなしに)クラスを関数として実行したいというケースも考えられる。たとえば次の例は、strict modeではnewキーワード無しにクラスを関数として実行した場合にthis変数がundefinedになることを利用し、newキーワード付きで実行した場合とnewキーワード無しで実行した場合とで異なる処理を行わせるものだ。

$ node --use_strict
> function Vector(x, y) {
... if (this === undefined) {
..... return new Vector(x, y);
..... }
... this.x = x;
... this.y = y;
... }
undefined
> Vector(3, 4)
Vector { x: 3, y: 4 }
> new Vector(3, 4)
Vector { x: 3, y: 4 }

 このようにして定義したVectorクラスは、newキーワードがあっても無くとも同様にVectorクラスのインスタンスを返す。

ECMAScript 2015の仕様書を読む(その22)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は付録について(付録A、D、Eについては詳細な内容は割愛)。

付録A

 文法まとめ。本編で説明されている文法がここでまとめられている。とりあえずここを見れば記述可能な文法が分かる。

付録B

 Webブラウザ向けの追加機能について。本来推奨されないが、Webブラウザ上で実行されるコードの互換性を保つために規定されているもので、Webブラウザ以外のECMAScript実行環境では実装しなくてもよい。また、これらはstrict modeでは利用できない。

 規定されているのは下記。

  • 数値リテラルにおける0で始まる8進数表記(本来であれば8進数表記は0Oで始まる必要がある)
  • 8進数表記を使ったエスケープシーケンス(バックスラッシュに続けて[0-8]もしくは[0-3][0-8]、[0-4][0-8]、[0-3][0-8][0-8])
  • HTML風コメント(を利用するもの)
  • Unicodeの基本多言語面(BMP)に関連する正規表現パターン
  • グローバルオブジェクトのescape(string)およびunescape(string)プロパティ
  • Object.prototype.proto
  • String.prototype.substr(start, length)
  • String.prototypeのanchor、big、blink、bold、fixed、fontcolor、fontsize、italics、link、small、strike、sub、supメソッド
  • Date.prototypeのgetYear、setYear、toGMTStringメソッド
  • RegExp.prototypeのcompileメソッド
  • オブジェクトの初期化時における__proto__プロパティの利用
  • ラベルを使った関数定義
  • ブロックレベルでの関数定義
  • ifステートメント内での関数定義
  • catchブロック内での重複した変数定義

 なお、escapeプロパティは[A-Za-z0-9@*_+-./]をURLエンコードする。

付録C

 ECMAScriptにおけるstrict modeについて。strict modeでは非strct modeと下記が異なる。

  • 予約語にimplements、interface、let、private、protected、public、static、yieldが追加されている
  • 付録Cで定義されているWebブラウザ向けの互換性維持のための文法や機能が利用できない
  • 宣言されていない識別子や参照先が存在しないリファレンスがグローバルオブジェクトのプロパティとして生成されない
  • 各種構文でeval、argumentsを左手側に置くことはできない
  • 関数内で引数が格納されるオブジェクト(argumentsオブジェクト)のcallerやcalleeプロパティ
  • argumentsオブジェクトに格納されている値と引数として渡される値は別
  • argumentsオブジェクトは変更不可
  • 「識別子 eval」や「識別子 arguments」はSyntaxErrorとなる
  • eval内ではそれを呼び出した環境の変数や関数のインスタンスを生成できない
  • thisの値がnullやundefinedだった場合、これらがグローバルオブジェクトに置き換えられることはく、またプリミティブ値が対応するラッパーオブジェクトに変換されることはない
  • 値や関数引数、関数名に対するdelete演算子の利用がSyntaxErrorに
  • Configurableでないプロパティに対するdelete演算子の利用がSyntaxErrorに
  • with文は利用できない
  • try〜catch文でcatchを構成する識別子がevalやargumentsだった場合、SyntaxErrorに
  • 関数定義の歳の引数パラメータで同じものを2つ以上使うとSyntaxErrorに
  • 関数のcallerやargumentsプロパティについてこの仕様書で規定されている以外の拡張をすべきではない

付録D

 過去のバージョンのECMAScriptから挙動が修正された点について。

付録E

 過去のバージョンのECMAScriptとは互換性のない変更について。

ECMAScript 2015の仕様書を読む(その21)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はリフレクションやプロキシ、モジュール名前空間に関連するオブジェクトに関する第26章。

第26章第1節

 Reflectオブジェクトについて。Reflectオブジェクトは内部オブジェクトとして定義されているオブジェクトで、グローバルオブジェクトのReflectプロパティの初期値になっている。関数オブジェクトではないので直接このオブジェクトを実行することはできないし、newキーワードを使って直接コンストラクタを呼び出すこともできない。

 Reflectオブジェクトは以下のプロパティ/メソッドを持つ。これらはObjectと同名のものもあるが、targetがオブジェクトでない場合必ずTypeErrorを発生させる点が異なる。

Reflect.apply(target, thisArgument, argumentsList)	target関数をargumentsListを引数として与えて実行する。このときthisにはthisArgumentが渡される
Reflect.construct(target, argumentsList [, newTarget])	targetを元に新たにオブジェクトを作成する。このときargumentsListを引数としてコンストラクタが実行される。newTargetがあ場合、これをコンストラクタとして使う。
Reflect.defineProperty(target, propertyKey, attributes)	targetにpropertyKeyという名前でプロパティを追加し、値にattributesをセットする
Reflect.deleteProperty(target, propertyKey)	targetのproprtyKeyプロパティを削除する
Reflect.enumerate(target)	targetのenumerableなプロパティに帯するiteratorを返す
Reflect.get(target, proertyKey [, receiver])	tagetのpropertyKeyプロパティを取得する。receiverが指定された場合、これをthisとして使用する
Reflect.getOwnPropertyDescriptor(target, propertyKey)	targetのpropertyKeyのPropertyDescriptorを返す
Reflect.getPrototypeOf(target)	targetのprototypeを返す
Reflect.has(target, propertyKey)	targetがpropertyKeyプロパティを持っていたらtrueを返す
Reflect.isExtensible(target)	targetがextensibleならtrue
Reflect.ownKeys(target)	targetが独自に持つプロパティキーの配列を返す
Reflect.preventExtensions(target)	targetの拡張を禁止する
Reflect.set(target, propertyKey, V [, receiver])	targetのpropertyKeyプロパティにVをセットする。receiverが与えられた場合、これをthisとする。
Reflect.setPrototypeOf(target, proto)	targetのプロトタイプをprotoに設定する

第26章第2節

 Proxyオブジェクトについて。Proxyオブジェクトは、あるオブジェクトについて、これを変更することなくそのプロパティやメソッドに対する挙動を追加・変更するために使われるオブジェクトである。

 ProxyオブジェクトはグローバルオブジェクトのProxyプロパティの初期値。Proxyコンストラクタは(target, handler)という引数を取り、targetをベースとした新たなproxyオブジェクトを作成する。このオブジェクトのプロパティにアクセスしたり、メソッドを実行しようとするとhandler関数が実行される。なおProxyオブジェクトは通常の関数としての実行は不可で、newキーワード無しで実行するとTypeErrorとなる。

 また、ProxyオブジェクトはProxy.revocable(target, handler)というメソッドを持つ。このメソッドは取り消し可能な(proxyを無効にできる)proxyオブジェクトを返す。このオブジェクトはproxy自体を格納するproxyプロパティおよびproxyを無効にするrevokeメソッドを持つ。

第26章第3節

 モジュール名前空間オブジェクト(Module Namespace Object)について。このオブジェクトはimportキーワードを使ってモジュールをロードした際に生成される。@@toStringTagプロパティおよび@@iteratorメソッドを持ち、前者は"Module"を返す。後者はモジュールの名前空間に登録されているキーに対するiteratorを返す。

ECMAScript 2015の仕様書を読む(その20)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はイテレータやジェネレータ、Promise関連のオブジェクトに関する第25章。

第25章1節

 イテレーションについて。iterate可能なオブジェクトは、@@iteratorプロパティでそのオブジェクトに対応するiteratorを取得できる。iteratorはnextメソッドを持ち、このメソッドを実行するとIteratorResultオブジェクトを返す。このオブジェクトは次のメソッドを持つ。これらはすべてIteratorResultオブジェクトを返す。

next

 また、オプションで次のプロパティを持つ。これらはすべてIteratorResultオブジェクトを返す。

return
throw

 returnは、それ以上nextメソッドを呼び出さないことをiteratorに通知する際に実行される。また、throwはiteratorに何らかのエラーが発生したことを通知するために使われる。throwは引数にexceptionオブジェクトなどのエラー内容を格納するオブジェクトを与えることができる。

 IteratorResultオブジェクトは次のプロパティを持つ。

done	iterateが完了するとtrue
value	対応する値を格納する

第25章2節

 GeneratorFunctionについて。GeneratorFunctionはFunctionオブジェクトの派生オブジェクトであり、Functionオブジェクトのコンストラクタから派生した独自のコンストラクタと、Iteratorのプロトタイプから派生した独自のprototypeを持つ。GeneratorFunctionはグローバルオブジェクトではないが、下記のコードを用いて取得できる。

Object.getPrototypeOf(function*(){}).constructor

 GeneratorFunctionは関数として実行できる。newキーワードを付けても付けなくても同じ挙動を行う。サブクラス化も可能だが、その際はコンストラクタ内でsuperキーワードを使ってGeneratorFunctionオブジェクトを生成する必要がある。また、GeneratorFunctionオブジェクトはfunction*キーワードで生成できる。

 GeneratorFunctionは次のような形式で実行できる。

GeneratorFunction(p1, p2, ..., pn, body)

 bodyは実行コード、p1〜pnはそれに与える引数の識別子である。これらは通常は文字列として与えられる。

また、lengthおよびprototypeというプロパティを持つ。lengthの値は1である。GeneratorFunction.prototypeは次のプロパティを持つ。

GeneratorFunction.prototype.constructor	内部オブジェクト
GeneratorFunction.prototype.prototype	内部オブジェクト
GeneratorFunction.prototype[@@toStringTag]	"GeneratorFunction"

 また、GeneratorFunctionインスタンスはlengthおよびname、prototypeプロパティを持つ。

第25章3節

 ジェネレータオブジェクトについて。このオブジェクトはジェネレータ関数のインスタンスであり、IteratorとIterableインターフェイスの両方の性質を持つ。このオブジェクトはジェネレータオブジェクトのprototypeではなく、インスタンスを作成したジェネレータ関数のprototypeを引き継ぐ。つまり、GeneratorオブジェクトのprototypeオブジェクトはGeneratorFunction.prototypeである。

 Generator.prototypeは次のプロパティ/メソッドを持つ。

Generator.prototype.constructor コンストラクタ
Generator.prototype.next(value)	ジェネレータ関数の状態をvalueにする
Generator.prototype.return(value)	valueを返して処理を終了させる
Generator.prototype.throw(exception)	ジェネレータ関数で例外を発生させる
Generator.prototype[@@toStringTag]	"Generator"

 ジェネレータ関数内では、yieldキーワードの戻り値を使っているケースがある。この場合、次にジェネレータ関数が呼び出された場合にその戻り値が関数内で続く処理に渡されるわけだが、nextメソッドを利用することでその値を変更できる。

第25章4節

 Promiseオブジェクトについて。Promiseオブジェクトは遅延・非同期処理を行うためのオブジェクト。内部的に「Resolve」と「Reject」の2つの関数オブジェクトを保持し、またfulfilled、rejected、pendingの3つのステータスのどれか1つを持つ。

 内部で非同期処理を行っている場合など、それが終了する時点では結果が分からない関数でPromiseオブジェクトを返り値として使用することが想定されている。このオブジェクトは処理が完了するとfulfilledもしくはrejectedのステータスとなり、ステータスを監視することで並列処理が完了したのか、またその結果がどうなったのかを知ることができる。

 Promiseオブジェクトは関数としては実行できない。newキーワード付きでコンストラクタとしての実行のみが許可される。Promiseオブジェクトのコンストラクタはサブクラス化可能であるが、その場合はsuperキーワードを使ってコンストラクタ内でPromiseオブジェクトを生成する必要がある。

 PromiseのコンストラクタはPromise(executor)という形で呼び出される。executorは関数オブジェクトであり、遅延・非同期処理が完了した際に呼び出される。また、resolveとrejectという2つの引数を持つ。いずれも関数オブジェクトで、executor関数内で処理が成功したのか、それとも失敗したのかを通知するために呼び出すことができる。また、executor関数の終了(returnの実行)は遅延・非同期処理の完了を意味するのでは無く、その処理が受け付けられたというのを示すだけである。

 引数として与えられるresolve関数は、1つの引数を取る。executor関数内で対応するPromiseオブジェクトの解決を行いたい際にこの関数が呼び出され、引数には遅延・非同期処理が進められる際に得られた値が渡される。

 引数として与えられるreject関数も1つの引数を取る。executor関数内で対応するPromiseオブジェクトがrejectされ、成功しないことが分かった際にこの関数が呼び出される。引数にはrejectされたことを示す値(一般的にはErrorオブジェクト)が渡される。

 Promiseオブジェクトは次のメソッド/プロパティを持つ。

Promise.all(iterable)	与えられたPromiseのすべてが成功した際に成功となる新たなPromiseオブジェクトを返す
Promise.prototype	内部オブジェクト
Promise.race(iterable)	与えられたPromiseのうち、最初に完了したPromiseと同じ結果を返す新たなPromiseオブジェクトを返す
Promise.reject(r)	与えられた引数によって失敗状態となる新たなPromiseオブジェクトを返す
Promise.resolve(x)	与えられた引数によって成功状態となる新たなPromiseオブジェクトを返す
Promise[@@species]	getter

 また、Promise.prototypeは下記のメソッド/プロパティを持つ。

Promise.prototype.catch(onRejected)	Promiseが失敗したときに実行されるコールバック関数を設定する
Promise.prototype.constructor	コンストラクタ
Promise.then(onFulfilled, onRejected)	成功した際および失敗した際に実行されるコールバック関数を設定する
Promise.prototype[@@toStringTag]	"Promise"

ECMAScript 2015の仕様書を読む(その19)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はArrayBufferおよびDataView、JSONオブジェクトについて規定する第24章。

第24章1節

 ArrayBufferオブジェクトについて。ArrayBufferは、処理系内部に確保された、任意の値を格納できるメモリバッファをラップするオブジェクトとなる。このオブジェクトは内部的にはデータを格納するメモリバッファと、そのバッファの長さを保持する。

 ArrayBufferコンストラクタはサブクラス化可能にデザインされている。その場合、サブクラスのコンストラクタ内ではsuperキーワードを使ってWeakMapコンストラクタを呼び出してインスタンスの初期化を行う必要がある。

 ArrayBufferをnewキーワード付きで関数として実行すると、ArrayBufferのインスタンスを生成できる。この際、引数にはバッファの長さを指定できる。newキーワード無しで実行するとTypeErrorとなる。

 ArrayBufferオブジェクトは下記のメソッド/プロパティを持つ。

ArrayBuffer.isView(arg)	argがViewedArrayBufferであればtrueを返す
ArrayBuffer.prototype	内部オブジェクト
ArrayBuffer[@@species]	getter。

 また、ArrayBuffer.prototypeは次のメソッド/プロパティを持つ。

ArrayBuffer.prototype.byteLength	getter。対応するバッファのバイト数を返す
ArrayBuffer.prototype.constructor	コンストラクタ
ArrayBuffer.prototype.slice(start, end)	対応するバッファのstartバイトからendバイトを新たに作成したArrayBufferにコピーして返す
ArrayBuffer.prototype[@@toStringTag]	"ArrayBuffer"

第24章2節

 DataViewオブジェクトについて。DataViewオブジェクトは対応するArrayBufferに格納されたデータにアクセスするためのメソッドを提供する。データへのアクセスはすべてNumber形式で行い、またコンストラクタで指定したbyteOffsetおよびbyteLengthの範囲を超える範囲へはアクセスできない。 

 ArrayBufferコンストラクタはサブクラス化可能にデザインされている。その場合、サブクラスのコンストラクタ内ではsuperキーワードを使ってWeakMapコンストラクタを呼び出してインスタンスの初期化を行う必要がある。

 DataViewオブジェクトをnewキーワード付きで関数として実行すると、DataViewオブジェクトのインスタンスを生成できる。引数はDataView(buffer [, byteOffset [, byteLength]])の最大3つ。bufferは対応付けるArrayBuffer(もしくはその派生オブジェクト)。byteOffset、ByteLengthはそれぞれバッファを参照する際のオフセットと、最大長さ。

 DataViewオブジェクトはprototypeプロパティのみを持つ。また、DataView.prototypeは次のメソッド/プロパティを持つ。

DataView.prototype.buffer	getter。対応付けられたArrayBufferを返す
DataView.prototype.byteLength	getter。参照できる最大バイト数を返す
DataView.prototype.byteOffset	getter。バッファを参照する際のオフセットを返す
DataView.prototype.constructor	コンストラクタ
DataView.prototype.getFloat32(byteOffset [, littleEndian])	対応付けられたバッファのbyteOffsetバイト目からのデータをFloat32として扱い、それをNumber形式に変換してデータを取り出す。littleEndianがtrueならリトルエンディアン、falseならビッグエンディアンで取り出す。以下、取り出す形式が異なるのみで同じ処理を行う
DataView.prototype.getFloat64(byteOffset [, littleEndian])	
DataView.prototype.getInt8(byteOffset)	
DataView.prototype.getInt16(byteOffset [, littleEndian])	
DataView.prototype.getInt32(byteOffset [, littleEndian])	
DataView.prototype.getUint8(byteOffset)	
DataView.prototype.getUint16(byteOffset [, littleEndian])	
DataView.prototype.getUint32(byteOffset [, littleEndian])	
DataView.prototype.setFloat32(byteOffset, value [, littleEndian])	対応付けられたバッファのbyteOffsetバイト目以降に、valueをFloat32として扱ってバイナリ化したものを書き込む。littleEndianがtrueならリトルエンディアン、falseならビッグエンディアンで取り出す。以下、取り出す形式が異なるのみで同じ処理を行う
DataView.prototype.setFloat64(byteOffset, value [, littleEndian])	
DataView.prototype.setInt8(byteOffset, value)	
DataView.prototype.setInt16(byteOffset, value [, littleEndian])	
DataView.prototype.setInt32(byteOffset, value [, littleEndian])	
DataView.prototype.setUint8(byteOffset, value)	
DataView.prototype.setUint16(byteOffset, value [, littleEndian])	
DataView.prototype.setUint32(byteOffset, value [, littleEndian])	
DataView.prototype[@@toStringTag]	"DataView"

第24章3節

 JSONオブジェクトについて。JSON形式で記述されたテキストベースのデータをオブジェクト化するもの。

 JSONオブジェクトはコンストラクタを持たないため、newキーワード付きでは実行できず、また関数として実行することもできない。

 JSONオブジェクトは次のメソッドを持つ。

JSON.parse(text [, reviver])	textをJSON文字列としてパースしECMAScriptオブジェクト/値を生成する。関数オブジェクトであるreviverが与えられた場合、この関数に対しthisとしてプロパティを含むオブジェクトを、引数にプロパティ名と値を与えて実行してこの値を変換できる
JSON.stringify(value, [, replacer [, space]])	valueをJSON文字列に変換する。関数オブジェクトであるreplacerが与えられた場合、引数にプロパティ名と値を与えて実行してその値を変換できる。spaceがtrueだった場合、変換結果を整形する。
JSON[@@toStringTag]	"JSON"

ECMAScript 2015の仕様書を読む(その18)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はWeakMapについて規定する第23章第3節とWeakSetについて規定する第4節。

第23章3節

 WeakMapはキー/値のペアを格納するオブジェクト。Mapとは異なり、キーにはオブジェクトしか使用できない。さらにWeakMapではキーを列挙する手段が提供されていない。WeakMapでは格納するキーに対し弱参照のみを保持する。そのため、キーとして使われたオブジェクトがgarbage collectionで回収された場合、WeakMap内からそのキーおよび対応付けられた値は削除される。

 WeakMapコンストラクタはサブクラス化可能にデザインされている。その場合、サブクラスのコンストラクタ内ではsuperキーワードを使ってWeakMapコンストラクタを呼び出してインスタンスの初期化を行う必要がある。

 WeakMapオブジェクトを関数として実行する場合、newキーワード付きで実行する必要がある。引数にはiterableなオブジェクトを取る。

 WeakMapオブジェクトはprototypeプロパティを持つ。WeakMap.prototypeオブジェクトは下記のメソッド/プロパティを持つ。

WeakMap.prototype.constructor	コンストラクタ
WeakMap.prototype.delete(key)	keyに対応するキー/値のペアを削除する
WeakMap.prototype.get(key)	keyに対応する値を返す
WeakMap.prototype.has(key)	keyに対応するキーがあればtrue
WeakMap.prototype.set(key, value)	keyに対応する値をvalueにセットする
WeakMap.prototype[@@toStringTag]	"WeakMap"

第23章4節

 WeakSetはオブジェクトのセットを格納するオブジェクト。Setとは異なり、オブジェクトしか格納できない。WeakMapと同様、格納されているオブジェクトを列挙する手段は提供されておらず、格納するオブジェクトに対し弱参照のみを保持する。

 WeakSetコンストラクタはサブクラス化可能にデザインされている。その場合、サブクラスのコンストラクタ内ではsuperキーワードを使ってWeakSetコンストラクタを呼び出してインスタンスの初期化を行う必要がある。

 WeakSetオブジェクトを関数として実行する場合、newキーワード付きで実行する必要がある。引数にはiterableなオブジェクトを取る。

 WeakSetオブジェクトはprototypeプロパティを持つ。WeakSet.prototypeオブジェクトは下記のメソッド/プロパティを持つ。

WeakSet.prototype.add(value)	valueをセットに追加する
WeakSet.prototype.constructor	コンストラクタ
WeakSet.prototype.delete(value)	valueに対応する値をセットから削除する
WeakSet.prototype.has(value)	valueがセット内にあればtrue
WeakSet.prototype[@@toStringTag]	"WeakSet"

ECMAScript 2015の仕様書を読む(その16)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はTypedArrayなどについて規定する第22章2節。

第22章2節

 TypedArrayはバイナリデータを格納するための配列状オブジェクト。格納可能な要素はInt8/Uint8/Uint8C/Int16/Uint16/Int32/Uint32/Float32/Float64のいずれかで、各要素はすべて同じ型である必要がある。各型ごとに異なる次の関数オブジェクトがコンストラクタとして用意されている。

Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array

 これらはすべて同じ引数を持ち、また同じprototypeを持つので、以下ではこれらのオブジェクトを%TypedArray%と表記する。

 %TypedArray%は異なる引数を持つ複数の形式で関数として呼び出せる。ただし、これらはすべてnewキーワード付き呼び出す必要がある。newキーワードなしで呼び出すと、TypeErrorを返す。

 コンストラクタに与えられる引数とその際の動作は下記のとおり。

%TypedArray%()	空のTypedArrayを返す
%TypedArray%(length)	指定した数の要素を持つTypedArrayを返す。各要素は0に設定される
%TypedArray%(typedArray)	typedArrayと同じ要素を持つTypedArrayを返す
%TypedArray%(object)	objectを元にTypedArrayを作成して返す
%TypedArray%(buffer [, byteOffset [, length]])	bufferのbtyeOffsetからlengthまでの部分を格納したTypedArrayを作成して返す

 %TypedArray%は下記のメソッド/プロパティを持つ。

%TypedArray%.from(source [, mapfn [, thisArg]])	sourceオブジェクトからTypedArrayを作成して返す。mapfnが指定された場合はこの関数を用いたmap処理が行われたあとに作成されたTypedArrayを返。
%TypedArray%.of(...items)	itemsを要素として持つTypedArrayを作成して返す
%TypedArray%[@@species]	gettter。thisを返す

 %TypedArray%.prototypeは下記のメソッド/プロパティを持つ。なお、とくに説明のないものについてはArray.prototypeの同名メソッド/プロパティと同じ処理を行う。

%TypedArray%.prototype.buffer	getter。格納するデータをbuffer形式で返す
%TypedArray%.prototype.byteLength	getter。格納するバイト数を返す
%TypedArray%.prototype.byteOffset	getter。byteOffsetを返す
%TypedArray%.prototype.constructor	コンストラクタ
%TypedArray%.prototype.copyWithin(target, start [, end])
%TypedArray%.prototype.entries()
%TypedArray%.prototype.every(callbackfn [, thisArg])
%TypedArray%.prototype.fill(value, [, start [, end]])
%TypedArray%.prototype.filter(callbackfn [, thisArg])
%TypedArray%.prototype.find(predicate [, thisArg])
%TypedArray%.prototype.findIndex(predicate [, thisArg])
%TypedArray%.prototype.forEach(callbackfn [, thisArg])
%TypedArray%.prototype.indexOf(searchElement [, fromIndex])
%TypedArray%.prototype.join(separator)
%TypedArray%.prototype.keys()
%TypedArray%.prototype.lastIndexOf(searchElement [, fromIndex])
%TypedArray%.prototype.length	格納する要素数
%TypedArray%.prototype.map(callbackfn [, thisArg])
%TypedArray%.prototype.reduce(callbackfn, [initialValue])
%TypedArray%.prototype.reduceRight(callbackfn, [initialValue])
%TypedArray%.prototype.set(overloaded [, offset])	第一引数からデータを読み込む。型によって処理が異なる
%TypedArray%.prototype.set(array [, offset])	arrayからデータを読み込む
%TypedArray%.prototype.set(typedArray [, offset])	typedArrayからデータを読み込む
%TypedArray%.prototype.slice(start, end)
%TypedArray%.prototype.some(callbackfn [, thisArg])
%TypedArray%.prototype.sort(comparefn)
%TypedArray%.prototype.subarray([begin [, end]])	部分配列を返す。この部分配列はバッファを共有する
%TypedArray%.prototype.toLocaleString([reserved1 [, reserved2]])
%TypedArray%.prototype.toString()
%TypedArray%.prototype.values()
%TypedArray%.prototype[@@iterator]()
%TypedArray%.prototype.[@@toStringTag]  getter。名前を返す

 なお、内部的に基底クラスとしてTypedArrayというものは存在するが、これをECMAScript 2015から直接操作することはできない。

 TypedArray.BYETS_PER_ELEMENTおよびTypedArray.prototype.BYTES_PER_ELEMENTで各要素のバイト数を参照できる。

ECMAScript 2015の仕様書を読む(その15)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は配列(Array)などについて規定する第22章第1節。

第22章第1節

 Arrayオブジェクトは特別なオブジェクトであり、例外的なプロパティ名を持つ。Arrayオブジェクトを関数として実行すると、新たなArrayオブジェクトを作成して返す。newキーワード付きの場合も同じ処理を行う。また、Arrayコンストラクタは拡張可能で、そのサブクラスはコンストラクタ内でsuperキーワードを使ってArrayコンストラクタを呼び出してオブジェクトを初期化する必要がある。

 Arrayコンストラクタは引数の数によって処理が変わる。引数が無い場合、空の配列を返す。1つの引数を与えた場合、その引数がNumberでかつその値がUint32に変換したものと等しい場合、長さがその値に等しく、かつ各要素がundefinedの配列を作成して返す。そうでない場合、その値を含む長さ1の配列を返す。2つ以上の引数が与えられた場合、それらを格納する配列を返す。

 Arrayオブジェクトは次のプロパティ/メソッドを持つ。

Array.from(items [, mapfs [, thisArg]])	mapfs関数にitems引数の各要素を与えて実行した結果を格納した配列を返す。また、thisArgが指定された場合、mapfsを実行時にそれをthisとして使用する。items引数はiterableなものであれば何でも良い
Array.isArray(arg)	argがArrayであればtrueを返す
Array.of(...items)	引数を値として格納した配列を返す

 Array.prototypeは内部オブジェクトであり、書き換えは不可能。また、Array[@@species]というアクセサプロパティを持つ。値はundefined。

 Array.prototypeプロパティは下記のプロパティ/メソッドを持つ。なお、thisArg引数はcallbackfnを実行する際にthisとして使用するオブジェクトである。また、startが負の場合、length+startが指定されたものとして処理が行われる。endが指定されなかった場合lengthが、endが負の場合length+endが指定されたものとして処理される。

Array.prototype.concat(...arguments)	引数を値として拝謁の末尾に追加する。引数が配列だった場合、その各要素を追加する
Array.prototype.constructor	コンストラクタ
Array.prototype.copyWithin(target, start [, end])	配列内のstartからendまでをtargetの位置から順に格納する
Array.prototype.entries()	[インデックス, 値]をvalue要素に格納するiteratorを返す
Array.prototype.every(callbackfn [, thisArg])	各要素を引数としてcallbackfnを実行し、すべてがtrueならtrueを返す
Array.prototype.fill(value [, start [, end]])	startからendまでの要素をvalueに設定する
Array.prototype.filter(callbackfn [, thisArg])	各要素を引数としてcallbackfnを実行し、trueを返したもののみを含む配列を作成して返す
Array.prototype.find(predicate [, thisArg])	各要素を引数としてpredicateを実行し、trueを返した場合その値を返す。predicateは要素、インデックス、対象の配列という3つの引数が与えられる
Array.prototype.findIndex(predicate [, thisArg])	findと同様の処理を行う。findとは異なり、インデックスを返す
Array.prototype.forEach(callbackfn [, thisArg])	各要素を引数としてcallbackfnを実行する。undefinedを返す
Array.prototype.indexOf(searchElement [, fromIndex])	searchElementと一致する要素のインデックスを返す。fromIndexが指定された場合、その位置から検索を開始する。比較には===演算子が使われる
Array.prototype.join(separator)	各要素を文字列に変換し、separatorを介して連結したものを返す。separatorがundefinedだった場合、","が使われる
Array.prototype.keys()	各キーをvalue要素に格納するiteratorを返す
Array.prototype.lastIndexOf(searchElement [, fromIndex])	searchElementと一致する最後の要素のインデックスを返す。fromIndexが指定された場合、その位置から検索を開始する。比較には===演算子が使われる
Array.prototype.map(callbackfn [, thisArg])	各要素を引数としてcallbackfnを実行し、その結果を含む配列を返す
Array.prototype.pop()	配列の最後の要素を削除してそれを返す
Array.prototype.push(...items)	引数として与えられた値をそれぞれ配列の最後に追加する
Array.prototype.reduce(callbackfn [, initialValue])	各要素を引数としてcallbackfnを実行する。callbackfnには直前に実行されたcallbackfnの戻り値、配列の要素、配列のインデックス、配列の4つの引数が与えられる。initialValueが指定された場合、それが最初に実行されるcallbackfnの第1引数となる。最後に実行されたcallbackfnの戻り値を返す
Array.prototype.reduceRight(callbackfn, [, initialValue])	reduceを逆方向に実行する
Array.prototype.reverse()	配列の要素の順序を逆にする
Array.prototype.shift()	配列の最初の要素を削除して返す
Array.prototype.slice(start, end)	startからendまでの要素を含む配列を返す
Array.prototype.some(callbackfn [, thisArg])	各要素を引数としてcallbackfnを実行し、いずれかがtrueを返したらtrueを返す
Array.prototype.sort(comparefn)	comparefnを比較関数としてソートを実行する
Array.prototype.splice(start, deleteCount, ...items)	startからdeleteCount個の要素を取り除き、そこにitemsで与えた各要素を追加する
Array.prototype.toLocaleString([reserved1 [, reserved2]])	ECMA-402で定義された地域課文字列を返す
Array.prototype.toString()	配列を文字列に変換する
Array.prototype.unshift(...items)	配列の最初に要素を追加しそのlengthを返す
Array.prototype.values()	各要素をvalue要素に格納するiteratorを返す
Array.prototype[@@iterator]()	valuesと同じ
Array.prototype[@@unscopables]	["copyWithin", "entries", "fill", "find", "findIndex", "includes", "keys", "values"]

 Arrayインスタンスはlengthプロパティを持つ。また、Arrayオブジェクトのiteratorはnext()のほか、[@@toStringTag]要素を持つ。

ECMAScript 2015の仕様書を読む(その14)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はテキスト処理関連について規定する第21章のうち、RegExpオブジェクトについて。

第21章2節

 RegExpオブジェクトは正規表現およびそれに関するフラグを格納するオブジェクト。Perl 5の正規表現をベースにしている。ECMAScriptで使える正規表現については詳しくまとめると大変なので省略。また、Perlとは異なり使える文字クラスは\d(数字)、\D(数字以外)、\s(ホワイトスペース)、\S(ホワイトスペース以外)、\w(アルファベットおよび数字、アンダースコア)、\W(アルファベットおよび数字、アンダースコア以外)の6つのみ。また、コントロールシーケンスは\t(HT)、\n(LF)、\v(VT)、\f(FF)、\r(CR)が定義されている。

 RegExpオブジェクトは(pattern, flags)という引数を取る。patternは正規表現リテラルもしくは文字列、flagsがフラグ。

 利用できるフラグはg(global)、i(ignoreCase)、m(multiline)、u(unicode)、y(sticky)。

 RegExpオブジェクトはRegExp[@@species]というアクセサを持つ。通常派生オブジェクトを作る際にこれを使用する。サブクラスを作る際にこの挙動を書き換えることも可能。

 RegExp.prototypeプロパティは下記のプロパティ/メソッドを持つ。

RegExp.prototype.constructor    コンストラクタ。初期値は内部オブジェクト
RegExp.prototype.exec(string)	stringに対しマッチを行う
RegExp.prototype.flags	アクセサ。設定されているフラグを返す
RegExp.prototype.global	アクセサ。gフラグが設定されていればtrue
RegExp.prototype.ignoreCase	アクセサ。iフラグが設定されていればtrue
RegExp.prototype[@@match](string)	String.prototype.matchメソッド内で内部的に呼び出されるマッチ関数
RegExp.prototype.multiline	アクセサ。mフラグが設定されていればtrue
RegExp.prototype[@@replace](string, replaceValue)	String.prototype.replaceメソッド内で内部的に呼び出される置換関数
RegExp.prototype[@@search](string)	String.prototype.searchメソッド内で内部的に呼び出されるマッチ関数
RegExp.prototype.source	アクセサ。正規表現を返す
RegExp.prototype[@@split](string, limit)	String.prototype.splitメソッド内で内部的に呼び出されるマッチ関数
RegExp.prototype.sticky	アクセサ。yフラグが設定されていればtrue
RegExp.prototype.test(S)	Sに対しマッチを行い、マッチしたらtrueを返す
RegExp.prototype.toString()	正規表現を文字列として返す
RegExp.prototype.unicode	アクセサ。uフラグが設定されていればtrue

 RegExpオブジェクトはlastIndexプロパティを持つ。これは、次のマッチ処理の際にどの位置からマッチ処理を行うべきかを格納する。

ECMAScript 2015の仕様書を読む(その13)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はテキスト処理関連について規定する第21章のうち、Stringオブジェクトについて。

第21章1節

 Stringオブジェクトのコンストラクタは内部オブジェクトが割り当てられているが、サブクラス化可能になっており、Stringオブジェクトのサブクラスはコンストラクタ内でsuperキーワードを使ってStringコンストラクタを実行しインスタンスを作成しなければならない。

 なお、Stringオブジェクトを関数として実行すると引数を文字列に変換したものを返す。また、newキーワード付きで関数として実行すると、引数を値として格納したStringオブジェクトを返す。

 Stringオブジェクトは次のプロパティ/メソッドを持つ。

String.fromCharCode(...codeUnits)	codeUnitsに相当する文字コードを含む文字列を返す。codeUnitsはUnicodeで指定。
String.fromCodePoint(...codePoints)	codePointsに相当する文字コードを含む文字列を返す
String.prototype	内部オブジェクトを指す。変更不可
String.raw(template, ...substitutions)	テンプレートオブジェクトに対し与えられた引数を使って展開を行う。通常はタグ付けされたテンプレート処理のために利用される

 また、String.prototypeオブジェクトは次のプロパティ/メソッドを持つ。

String.prototype.charAt(pos)	posの位置にある文字を返す
String.prototype.charCodeAt(pos)	posの位置にある文字の文字コードを返す
String.prototype.codePointAt(pos)	posの位置にある文字のコードポイントを返す
String.prototype.concat(...args)	argsを連結した文字列を返す
String.prototype.constructor	コンストラクタ。内部オブジェクト
String.prototype.endsWith(searchString [, endPosition])	文字列がsearchStringで終わっていればtrueを返す。endPositionを指定した場合、文字列がその長さであるかのように処理を行う
String.prototype.(includes)sesarchString [, position])	文字列がsearchStringを含んでいればtrueを返す。positionが指定された場合、その位置から検索を開始する
String.prototype.indexOf(searchString [, position])	文字列中でsearchStringが最初に出現する位置を返す。positionが指定された場合、その位置から検索を開始する
String.prototype.lastIndexOf(searchString [, position])	文字列中でsearchStringが最後に出現する位置を返す。positionが指定された場合、その位置から検索を開始する
String.prototype.localeCompare(tha [, reserved1 [, reserved2]])	ECMA-402で規定されているlocaleCompare処理を行う。
String.prototype.match(regexp)	regexpを使ってマッチ処理を行う
String.prototype.normalize([form])	文字列を正規化したものを返す。formは"NFC"、"NFD"、"NFKC"、"NFKD"が指定可能
String.prototype.repeat(count)	文字列をcount回繰り返したものを返す
String.prototype.replace(searchValue, replaceValue)	serachValueをreplaceValueに置き換える。replaceValueには$$、$&、$`、$'、$n、$nnなどが指定可能
String.prototype.search(regexp)	文字列中でregexpにマッチした位置を返す
String.prototype.slice(start, end)	startの位置からendの位置までの部分文字列を返す。endが負の場合、文字列のlengthにendを足したものがendとして使われる
String.prototype.split(separator, limit)	separatorで文字列を分割する
String.prototype.startsWith(searchString [, position])	文字列がsearchStringで始まっているならtrueを返す。positionが指定されていた場合、その場所から検索を開始する
String.prototype.substring(start, end)	startの位置からendの位置までの部分文字列を返す。endがstartより小さい場合、endとstartは入れ替えられる
String.prototype.toLocaleLowerCase([reseved1 [, reserved2]])	ECMA-402で規定されているtoLocaseLowerCase処理を行う。
String.prototype.toLocaleUpperCase([reseved1 [, reserved2]])	ECMA-402で規定されているtoLocaseUpperCase処理を行う。
String.prototype.toLowerCase()	小文字に変換した文字列を返す
String.prototype.toString()	変換した文字列を返す
String.prototype.toUpperCase()	大文字に変換した文字列を返す
String.prototype.trim()	前後のホワイトスペースをものを返す
String.prototype.valueOf()	変換した文字列を返す
String.prototype[@@iterator]()	文字列のコードポイントを走査するためのiteratorを返す

 また、Stringインスタンスはその文字列の長さを格納するlengthプロパティを持つ。

 Stringはiteratorを使った走査にも対応している。このiteratorは、文字列をインデックス順に返す。

ECMAScript 2015の仕様書を読む(その12)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はNumber、Math、Dateオブジェクトについて解説する第20章のうち、Dateオブジェクトについて。

第20章3節

 ECMAScriptでは基準時刻(UTC1970年1月1日)からのミリ秒で時刻を表現する。表現できるのはこの基準時刻±9,007,199,254,740,992(2の53乗)ミリ秒であり、これはおよそ±28万5,616年に相当する。ただし、実際にDateオブジェクトで扱えるのは1970年1月1日正午から±1億日(±8,640,000,000,000,000ミリ秒)。

 なお、1日は8640万ミリ秒。また、閏秒は考慮されないが、閏年は考慮される。月については0〜11(0が1月)の値で表現されるが、日は1〜31の値で表現される。曜日は0〜6(0が日曜日)。そのほか、ECMAScript処理系はタイムゾーンの処理や夏時間なども考慮する。

 ECMAScriptはISO 8601 Extended Formatベースのフォーマット仕様(YYYY-MM-DDTHH:mm:ss.sssZ)をサポートする。なお、年については最大6桁(および±)での表現が可能。

 Dateオブジェクトは、基準時刻からのミリ秒をそのオブジェクトの値として格納する。また、Dateオブジェクトのコンストラクタは内部オブジェクトになっている。このコンストラクタはサブクラス化が可能だが、その場合superキーワードを使ってDataコンストラクタをコンストラクタ内で呼び出す必要がある。

 デフォルトのDateコンストラクタは3つのパターンがある。どの場合もnewキーワードなしで呼ばれた場合、いかなる引数が与えられていても現在時刻に相当する文字列を返す。

 2つ以上の引数を取るケースは以下。この場合、引数で指定した日付時刻に相当するDateオブジェクトを返す。また、引数にNaNがあると「不正な時刻」に相当するDateオブジェクトを返す。

Date(year, month [, date [, hours [, minutes [, seconds [, ms]]]]])

 1つの引数を与えた場合、引数として与えられたオブジェクトが日付時刻値を格納していた場合はその日付時刻に相当するDateオブジェクトを、もし引数が文字列であり、かつ日付時刻としてパースできる場合はその日付時刻に相当するDatetオブジェクトを、そうでない場合は引数を数値に変換し、基準時刻にその数値を足した日付時刻に相当するDateオブジェクトを返す。

 引数が与えられなかった場合、現在の日付時刻に相当するDateオブジェクトを返す。

 Dateオブジェクトは次のメソッドを持つ。

Date.now()	基準時刻から現在時刻までの経過ミリ秒を返す
Date.parse(string)	引数を文字列としてパースし、基準時刻からその時刻までの経過ミリ秒を返す

 また、Dateオブジェクトのprototypeオブジェクトは下記のメソッド/プロパティを持つ。

Date.prototype.constructor	コンストラクタ
Date.prototype.getDate()	そのオブジェクトの日にちを返す(下記、同様)
Date.prototype.getDay()	
Date.prototype.getFullYear()	
Date.prototype.getHours()	
Date.prototype.getMilliseconds()	
Date.prototype.getMinutes()	
Date.prototype.getMonth	
Date.prototype.getSeconds()	
Date.prototype.getTime()	基準時刻からの経過ミリ秒を返す
Date.prototype.getTimezoneOffset()	UTCからローカル時刻へのオフセット(分)を返す
Date.prototype.getUTCDate()	そのオブジェクトのUTCでの日にちを返す(下記、同様)
Date.prototype.getUTCDay()
Date.prototype.getUTCFullYear()
Date.prototype.getUTCHours()
Date.prototype.getUTCMilliseconds()
Date.prototype.getUTCMinutes()
Date.prototype.getUTCMonth()
Date.prototype.getUTCSeconds()
Date.prototype.setDate(date)	そのオブジェクトの日付をdateに設定する(下記、同様)
Date.prototype.setFullYear(year [, month [, date]])
Date.prototype.setHours(hour [, min [, sec [, ms]]])
Date.prototype.setMilliseconds(ms)
Date.prototype.setMinutes(min [, sec [, ms]])
Date.prototype.setMonth(month [, date])	
Date.prototype.setSeconds(sec [, ms])	
Date.prototype.setTime(time)	
Date.prototype.setUTCDate(date)	そのオブジェクトのUTCでの日付をdateに設定する(下記、同様)
Date.prototype.setFUTCullYear(year [, month [, date]])
Date.prototype.setUTCHours(hour [, min [, sec [, ms]]])
Date.prototype.setUTCMilliseconds(ms)
Date.prototype.setUTCMinutes(min [, sec [, ms]])
Date.prototype.setUTCMonth(month [, date])	
Date.prototype.setUTCSeconds(sec [, ms])	
Date.prototype.toDateString()	相当する文字列を返す
Date.prototype.toISOString()	相当する文字列(ISO 8601 Extended Format)を返す
Date.prototype.toJSON(key)	JSONで使われる日付時刻文字列を返す
Date.prototype.toLocalDateString([ reserved1 [, reserved2]])	ローカル日付文字列を返す
Date.prototype.toLocalString([ reserved1 [, reserved2]])	ローカル文字列を返す
Date.prototype.toLocalTimeString([ reserved1 [, reserved2]])	ローカル時刻文字列を返す
Date.prototype.toString()	相当する文字列を返す
Date.prototype.toTimeString()	相当する時刻文字列を返す
Date.prototype.toUTCString()	相当するUTC文字列を返す
Date.prototype.valueOf()	基準時刻からの経過ミリ秒を返す
Date.prototype.toPrimitive[@@toPrimitive](hint)	相当するプリミティブ値を返す。hintは"default"もしくは"number"、"string"のどれか。"default"は"string"と同等。

ECMAScript 2015の仕様書を読む(その11)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はNumber、Math、Dateオブジェクトについて解説する第20章のうち、Mathオブジェクトについて。

第20章第2節

 Mathオブジェクトについて。Mathオブジェクトは関数オブジェクトではないため、関数としてもnewキーワード付きでも実行できない。

 Mathオブジェクトは多数のプロパティ/メソッドを持つ。まず、数値演算で使われる次のような定数が定義されている。これらはすべて書き込み禁止で列挙もされない。また、Math[@@toStringTag]のみConofigurableである。

Math.E	ネイピア数(e、exp(1))
Math.LN10	log(10)
Math.LN2	log(2)
Math.LOG10E	log10(e)
Math.LOG2E	log2(e)
Math.PI	円周率
Math.SQRT1_2	√(1/2)
Math.Math.SQRT2	√2
Math[@@toStringTag]	"Math"という文字列

 また、次のような数学関数をメソッドとして持つ。

Math.abs(x)	絶対値
Math.acos(x)	アークコサイン
Math.acosh(x)	逆双曲線コサイン
Math.asin(x)	アークサイン
Math.asinh(x)	逆双曲線サイン
Math.atan(x)    アークタンジェント
Math.atanh(x)   逆双曲線タンジェント
Math.atan2(x, y)	atan(y/x)
Math.cbrt(x)	立方根
Math.ceil(x)    x以上の最小の整数
Math.clz32(x)	xを2進数表示し、その戦闘から続く0の桁数
Math.cos(x)	コサイン
Math.cosh(x)	双曲線コサイン
Math.exp(x)	eのx乗
Math.expm1(x)	eのx乗 - 1
Math.floor(x)	x以下の最小の整数
Math.fround(x)	xに最も近い32ビット浮動小数点数を返す
Math.hypot(value1, value2, value3, ...values)	引数で与えた値の2乗和平方根を返す
Math.imul(x, y)	xとyを整数に変換したものの積を返す
Math.log(x)	eを底とするxの対数
Math.log1p(x)	log(x) + 1
Math.log10(x)	10を底とするxの対数
Math.log2(x)	2を底とする2の対数
Math.max(value1, value2, value3, ...values)	引数の中で最大の数を返す。引数が与えられなかった場合は-Infinityを、NaNが含まれていた場合はNaNを返す
Math.min(value1, value2, value3, ...values)	引数の中で最小の数を返す。引数が与えられなかった場合は-Infinityを、NaNが含まれていた場合はNaNを返す
Math.pow(x, y)	xのy乗を返す
Math.random()	0以上1以下の乱数を返す
Math.round(x)	xに最も近い整数を返す(xの小数点1桁目を四捨五入する)
Math.sign(x)	xが0より大きければ1、0なら0、0より小さければ-1を返す
Math.sin(x)	サイン
Math.sinh(x)	双曲線サイン
Math.sqrt(x)	平方根
Math.tan(x)	タンジェント
Math.tanh(x)	双曲線タンジェント
Math.trunc(x)	xの整数部分を返す

ECMAScript 2015の仕様書を読む(その10)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回はNumber、Math、Dateオブジェクトについて解説する第20章のうち、Numberオブジェクトについて。

第20章第1節

 Numberオブジェクトについて。Numberオブジェクトは基本型であるNumberに対応するオブジェクト。サブクラスを作って拡張可能となっている。サブクラスを作る場合、コンストラクタ内でsuperキーワードを使ってNumberオブジェクトのコンストラクタを実行することが推奨されている。

 Numberオブジェクトを関数として実行すると、引数を数値化したものを返す。引数が与えられなかった場合は0を返す。また、newキーワード付きで実行されると引数を数値化したものを値として格納する新たなNumberオブジェクトを作成して返す。なお、このコンストラクタは内部オブジェクトを参照している。

 Numberオブジェクトが持つプロパティやメソッドは下記の通り。

Number.EPSILON	「1と1より大きい最小の数の差」を示す定数
Number.isFinite(number)	numberがNaN、Infinity、-Infinity以外の数であればtrueを返す
Number.isInteger(number)	numberが整数であればtrueを返す
Number.isNaN(number)	numberがNaNであればtrueを返す
Number.isSafeInteger(number)	numberが整数で、かつその絶対値がNumber.MAX_SAFE_INTEGER以下であればtrueを返す
Number.MAX_SAFE_INTEGER	2の53乗-1。Number型では整数はこの数+1までしか表現できない
Number.MAX_VALUE	Number形で扱える最大の数。約1.7976931348623157×10の308乗
Number.MIN_SAFE_INTEGER	-(2の53乗-1)。Number型では整数はこの数-1までしか表現できない
Number.MIN_VALUE	Number形で扱える最小の数。約5×10の-324乗
Number.NaN	NaN	
Number.NEGATIVE_INFINITY	-Infinity
Number.paseFloat(string)	parseFloat(string)と同等
Number.parseInt(string, radix)	parseFloat(string, radix)と同等
Number.POSITIVE_INFINITY	Infinity
Number.prototype	初期値は内部オブジェクト

 なお、Number.isNaNはisNaNとは異なり、引数としてNaNが与えられた場合のみtrueを返す。

> isNaN("fo")
true
> Number.isNaN("fo")
false

 また、Number.MAX_SAFE_INTEGER+1を超える整数、もしくはNumber.MIN_SAFE_INTEGER-1よりも小さい整数は次の例のように演算結果が保証されない。

> Number.MAX_SAFE_INTEGER 
9007199254740991
> Number.MAX_SAFE_INTEGER + 1
9007199254740992
> Number.MAX_SAFE_INTEGER + 2
9007199254740992
> Number.MAX_SAFE_INTEGER + 3
9007199254740994

 Number.prototypeの持つプロパティ/メソッドは下記になる。

Number.prototype.constructor	コンストラクタ。初期値は内部オブジェクト
Number.prototype.toExponential(fractionDigits)	指数表記した文字列に変換して返す。このとき、小数点以下はfractionDigitsで指定した桁数となる
Number.prototype.toFixed(fractionDigits)	固定小数点表記した文字列に変換して返す。このとき、小数点以下はfractionDigitsで指定した桁数となる
Number.prototype.toLocaleString([reserved1 [, reserved2]])	ECMA-402規格で定義されたローカリゼーションされた文字列を返す
Number.prototype.toPrecision(precision)	precisionで指定した桁数の文字列に変換して返す
Number.prototype.toString([radix])	文字列に変換して返す。radixが指定された場合、radix進数表記で返す
Number.prototype.valueOf()	値を返す

 なお、数値型はNumberオブジェクトでありNnumber.prototypeを継承する。

ECMAScript 2015の仕様書を読む(その9)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は基本オブジェクト(Fundamental Objects)についての第19章のうち、Boolean、Symbol、Errorオブジェクトについて。

第19章第3節

 Booleanオブジェクトおよびそのメソッド、プロパティについて説明されている。

 Booleanオブジェクトは関数として実行すると、引数として与えたオブジェクトの真偽値に対応したtrueもしくはfalseを返す。また、newキーワード付きで実行するとその真偽値に対応したBooleanオブジェクトを返す。

 Booleanオブジェクトはprototypeプロパティのみを持つ。初期値は内部オブジェクトとなる。このプロパティの書き換えや属性変更は行えない。また、Boolean.prototypeは下記のプロパティ/メソッドを持つ。

Boolean.prototype.constructor	コンストラクタ。初期値は内部オブジェクト
Boolean.prototype.toString()	格納されている値に応じて"true"もしくは"false"を返す
Boolean.prototype.valueOf()	格納されている値に応じてtrue/falseを返す

第19章第4節

 Symbolオブジェクトおよびそのメソッド、プロパティについて説明されている。SymbolはECMAScript2015で新たに導入された基本オブジェクトで、オブジェクトのプロパティを参照するためのキーとして使用することが想定されている。

 Symbolオブジェクトをそのまま関数として実行すると、ユニークなSymbolオブジェクトを作成して返す。このとき、作成されたオブジェクトの[[Description]]内部スロットに引数として与えたオブジェクトを文字列に変換したものが格納される。また、newキーワード付きで実行するとTypeError例外を発生させる。

 Symbolオブジェクトは下記のプロパティ/メソッドを持つ。

Symbol.for(key)	GlobalSymbolRegistryを検索し、keyに対応するSybolがあればそれを返す。無ければ、新たなSymbolを作成し、GlobalSymboその[[key]]内部スロットおよび[[symbol]]内部スロットにkeyを文字列に変換したものを設定する。GlobalSymbolRegistryにkeyをキーとしてこのSymbolを登録し、このSymbolを返す
Symbol.hasInstance	@@hasInstanceシンボルが格納されている
Symbol.isConcatSpreadable	@@isConcatSpreadableシンボルが格納されている
Symbol.iterator	@@iteratorシンボルが格納されている
Symbol.keyFor(sym)	GlobalSymbolRegistryを検索し、symシンボルに対応するkeyがあればそれを返す。なければundefinedを返す
Symbol.match	@@matchシンボルが格納されている
Symbol.prototype	初期値では内部オブジェクトが格納されている
Symbol.replace	@@replaceシンボルが格納されている
Symbol.search	@@searchシンボルが格納されている
Symbol.spicies	@@spiciesシンボルが格納されている
Symbol.split	@@splitシンボルが格納されている
Symbol.toPrimitive	@@toPrimitiveシンボルが格納されている
Symbol.toStringTag	@@toStringTagシンボルが格納されている
Symbol.unscopables	@@unscopablesシンボルが格納されている

 なお、GlobalSymbolRegistryはグローバルな内部変数。

 Symbol.prototypeは下記のプロパティ/メソッドを持つ。

Symbol.prototype.constructor	コンストラクタ。初期値は内部オブジェクト
Symbol.prototype.toString()	"Symbol ([[Description]])"という文字列を返す
Symbol.prototype.valueOf()	そのシンボル自体を返す。オブジェクトがSymbolオブジェクトで内場合、[[SymbolData]]内部スロットの値を返す
Symbol.prototype[@@toPrimitive](hint)	Symbolオブジェクトをプリミティブ値に変換したものを返す。hintは"default"もしくは"number"、"string"
Symbol.prototype[@@toStringTag]	初期値は"Symbol"

 [[SymbolData]]内部スロットは、そのSymbolオブジェクトの内容を示す値が格納されているもの。

第19章第5節

 Errorオブジェクトおよびそのメソッド、プロパティについて説明されている。Errorオブジェクトは例外が発生した際にランタイムによって生成されるほか、ユーザー定義例外の基本オブジェクトとしても使われる。

 Errorオブジェクトをそのまま関数として実行すると、新たなErrorオブジェクトを生成して返す。このとき、引数に与えたオブジェクトを文字列化してmeessageプロパティの値に設定する。また、newキーワード付きで実行した場合も同じ挙動を行う。

 なお、Errorオブジェクトのコンストラクタはそのサブクラスを作れるように設計されている。その場合、コンストラクタ内ではsuperキーワードを使ってErrorオブジェクトを作成・初期化することが推奨されている。

 Errorオブジェクトは下記のプロパティ/メソッドを持つ。

Error.prototype	初期値では内部オブジェクトが格納されている

 Error.prototypeは下記のプロパティ/メソッドを持つ。

Error.prototype.constructor	コンストラクタ。初期値は内部オブジェクト
Error.prototype.message	初期値は空の文字列
Error.prototype.name	初期値は"Error"
Error.prototype.toString()	"<name>: <message>"という文字列を返す

 なお、ECMAScript2015ではネイティブエラーオブジェクトとして下記が用意されている。

EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError

 これらのオブジェクトもサブクラス化が可能となっている。

ECMAScript 2015の仕様書を読む(その8)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は基本オブジェクト(Fundamental Objects)についての第19章のうち、Functionオブジェクトについて。

第19章第2節

 Functionオブジェクトおよびそのメソッド、プロパティについてが説明されている。

 Functionオブジェクトは関数として呼び出すことで、関数オブジェクトを返す。この場合、常にFunctionオブジェクトのコンストラクタとして関数は実行されるため、newキーワードを付けても付けなくても同じ結果となる。

 Functionオブジェクトを関数として実行する場合、以下のような引数を取る。

Function(p1, p2, ..., pn, body)

 p1〜pnはその関数に与える仮引数リスト、bodyは関数本体である。戻り値はFunctionオブジェクトとなる。なお、仮引数リストは文字列で与えられる。このとき、1つの引数に複数の仮引数を入れることが可能。たとえば以下の3つは同じものを返す。

new Function("a", "b", "c", "return a+b+c")
new Function("a, b, c", "return a+b+c")
new Function("a,b", "c", "return a+b+c")

 Functionオブジェクトは以下のプロパティを持つ。

Function.length	1を返す
Funtion.prototype	内部オブジェクトが割り当てられている

 また、Function.protoypeオブジェクトは内部オブジェクトであるため、関数として実行すると常にundefinedを返す。また、下記のプロパティを持つ。

Function.prototype.apply(thisArg, argArray)	thisArgをthis変数に設定し、argArrayを引数として関数を実行する
Function.prototype.bind(thisArg, ...args)	thisArgをthis変数に設定し、argsを引数として呼び出される束縛関数を作成して返す
Function.prototype.call(thisArg, ...args)	thisArgをthis変数に設定し、argを引数として関数を実行する
Function.prototype.constructor	コンストラクタ関数。初期値は内部オブジェクト
Function.prototype.toString()	オブジェクトの内容を示す文字列を返す
Function.prototype[@@hasInstance](V)	v instanceof Fに相当

 なお、Functionオブジェクトのインスタンスはlength、name、prototypeというプロパティを持つ。lengthは関数の引数の数、nameは関数名が格納されている。

ECMAScript 2015の仕様書を読む(その7)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は基本オブジェクト(Fundamental Objects)についての第19章のうち、Objectオブジェクトについて。

第19章第1節

 ECMAScript 2015では基本オブジェクトとしてObject、Function、Boolean、Symbol、Errorの5つのオブジェクトが用意されている。どのオブジェクトも関数オブジェクトであり、コンストラクタとして呼び出すことができる。第1節では、Objectオブジェクトについて説明されている。

 Objectオブジェクトをnewキーワードを付けずに関数として呼び出すと、その引数をオブジェクト化したものを返す。たとえば数値を引数に与えた場合、その数値をNumberオブジェクトにしたものを返す。引数がnullやundefinedだった場合は新たに空のオブジェクトを作成して返す。また、newキーワード付きで呼び出すと、その引数で指定したオブジェクトのコンストラクタにその引数を与えて実行した結果を返す。たとえば、「new Object(“hoge”)」は「new String(“hoge”)」と同じ結果となる。

 Objectオブジェクトは次のメソッド/プロパティを持つ。

Object.assign(target, ...sources)	sourcesオブジェクトのenumerableなプロパティを、その添え字をキー、値を値としてtargetオブジェクトにコピーする。戻り値はtargetオブジェクト
Object.create (O[, Properties])	Oオブジェクトを元に新しいオブジェクトを作成する
Object.defineProperties(O, Properties)	Oオブジェクトにプロパティを追加する。そのプロパティがすでに定義されていた場合は指定されたものに更新する。Propertiesはキーとして対象のプロパティ、値としてそのプロパティの情報(ディスクリプタ)を格納したオブジェクトを持つオブジェクト
Object.defineProperty(O, P, Attributes)	OオブジェクトにPプロパティを追加する。Attributesはそのプロパティの情報を格納したオブジェクト(ディスクリプタ)
Object.freeze(O)	Oオブジェクトをフリーズする。フリーズされた(frozen)オブジェクトは変更ができなくなる
Object.getOwnPropertyDescriptor(O, P)	OオブジェクトのPプロパティのディスクリプタを返す
Object.getOwnPropertyNames(O)	Oオブジェクトのプロパティ名一覧を含む配列を返す
Object.getOwnProertySymbols(O)	Oオブジェクトのシンボル一覧を含む配列を返す
Object.getPrototypeOf(O)	Oオブジェクトのプロトタイプを返す
Object.is(value1, value2)	value1とvalue2が同じ値であればtrueを返す
Object.isExtensible(O)	Oオブジェクトが拡張可能であればtrueを返す
Object.isFrozen(O)	Oオブジェクトがフリーズされていればtrueを返す
Object.isSealed(O)	Oオブジェクトがsealed状態であればtrueを返す
Object.keys(O)	Oオブジェクトのプロパティ名一覧を含む配列を返す
Object.preventExtensions(O)	Oオブジェクトの拡張を禁止する。拡張が禁止されたオブジェクトには、新たなプロパティを追加できなくなる
Oject.prototype	オブジェクトのプロトタイプを格納するプロパティ
Object.seal(O)	Oオブジェクトをsealed状態にする。sealed状態のオブジェクトに対しては新たなプロパティを追加できず、またプロパティの設定を変更できなくなる
Object.setProtptypeOf(O, proto)	Oオブジェクトのプロトタイプをprotoオブジェクトに変更する

 オブジェクトのプロパティには「データプロパティ(Data Property)」と「アクセサプロパティ(Accessor Proerty)」がある。Dataプロパティは「Value」「Writable」「Enumerable」「Configurable」という属性を持つ。また、アクセサプロパティは「Get」「Set」「Enumerable」「Configurable」という属性を持つ(6.1.7.1)。これら属性を設定/変更するのがdefinePropertiesやdefineProperty。各属性の説明は下記の通り。

Value	そのプロパティに設定された値
Writable	プロパティへの値の書き込みが可能かどうか(Boolean)
Enumerable	そのプロパティがfor-inループでの列挙対象となるか(Boolean)
Configurable	そのプロパティの削除や属性変更が可能かどうか(Boolean)
Get	プロパティに対応するgetter関数
Set	プロパティに対応するsetter関数

 これらを以下のような形で格納したオブジェクトはプロパティディスクリプタと呼ばれる。

{
  value: 値,
  writable: (true|false),
  enumerable: (true|false),
  ...
}

 オブジェクトには拡張の不可や「frozen」や「sealed」といった「Ingegrity Level」を設定できる。まず拡張の不可だが、拡張が不可である場合オブジェクトに新しいプロパティを追加できなくなる(削除は可能)。また、sealed状態のオブジェクトは拡張不可となり、さらに各プロパティの属性が変更不可能になる(プロパティのconfigurable属性がfakseになる)。データプロパティの値を変更することは可能。いっぽうfrozen状態のオブジェクトは拡張不可で各プロパティの属性は変更できなくなる点はsealedと同じだが、さらにデータプロパティの値変更も不可となる(プロパティのwritable属性がfalseになる)。ただし、setter/getterについては実行可能。

 また、Object.prototypeオブジェクトは次のメソッド/プロパティを持つ。

Object.prototype.constructor	オブジェクトのコンストラクタ。デフォルトはObjectに相当する内部オブジェクト
Object.prototype.hasOwnProperty(V)	Vプロパティを持っていればtrue
Object.prototype.isPrototypeOf(V)	Vオブジェクトのプロトタイプがオブジェクトのプロトタイプと一致すればtrueを返す
Object.prototype.propertyIsEnumerable(V)	Vプロパティが列挙可能であればtrueを返す
Object.prototype.toLocaleString([reserved1[ , reserved2]])	オブジェクトのtoStringメソッドを実行しその結果を返す。現状Array、Number、Date、Typed Arraysのみが固有のtoLocaleStringを持つ
Object.prototype.toString()	オブジェクトが持つ情報を文字列に変換して返す
Object.prototype.valueOf()	オブジェクトのプリミティブ値を返す

ECMAScript 2015の仕様書を読む(その6)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。エラー処理および言語仕様の拡張についての第16章、標準組み込み(ビルトイン)オブジェクトについての第17章、グローバルオブジェクトについての第18章。

第16章

 エラー処理についてと言語仕様の拡張について。「early error」という種別のエラーが検出されたら、その時点でスクリプトの評価を止めてそれを通知する。また、モジュール内でのearly errorが検出されたら、その時点でモジュールの評価は中止されモジュールは初期化されない。evalキーワードでスクリプトが実行された際にearly errorが発生した場合、その評価をその時点で終了される。

 このearly errorの発生条件は仕様書内に細かく記載されているが、いわゆる文法エラーがこれに相当する。なお、ECMAScriptの処理系はSyntax ErrorおよびReferenceError以外のエラーについては詳細にそれをレポートするべきである。

 言語仕様の拡張については、16.1で拡張してはいけない仕様についてが説明されている。こちらについては一般的にコードを書く際には知識は不要なので割愛。

第17章

 ECMAScriptの標準ビルトインオブジェクトについて。

  • 標準ビルトインオブジェクトの多くは関数オブジェクト
  • 関数オブジェクトのうち、一部はnew演算子付きで実行することが想定されているコンストラクタ
  • ビルトイン関数には必要な引数よりも少ない引数を与えることができる。その場合、足りない引数にはundefinedが渡される
  • 必要な引数よりも多い引数を与えることもできる。通常それは関数の実行時に評価はされるが、その後は無視される。ただし、このとき実装側でTypeError例外を投げることも許可されている
  • ビルトイン関数オブジェクトはlengthプロパティを持つ。このプロパティには、その関数に与える最大の名前付き引数の数が格納されている

第18章

 グローバルオブジェクトについて。グローバルオブジェクトは、コード実行が開始される前に作成される。これらオブジェクトをnew演算子で作成することはできないし、関数として実行することもできない。ECMAScript 2015ではいくつかのグローバルオブジェクトが規定されているほか、処理系によって独自のグローバルオブジェクトを用意することも許されている。

 ECMAScript 2015で定義されているグローバルオブジェクトは次の通り。まず値を示すオブジェクトが3つ。

  • Infinity
  • NaN
  • undefined

 いくつかの関数オブジェクト。

  • eval(x)
  • isFinite(number)
  • isNaN(number)
  • parseFloat(string)
  • parseInt(string, radix)
  • decodeURI(encodedURI)
  • decodeURIComponent(encodedURIComponent)
  • encodeURI(uri)
  • encodeURIComponent(uriComponent)

 いくつかのグローバルオブジェクトのコンストラクタ。

  • Array()
  • ArrayBuffer()
  • Boolean()
  • DataView()
  • Date()
  • Error()
  • EvalError()
  • Float32Array()
  • Float64Array()
  • Function()
  • Int8Array
  • Int16Array
  • Int32Array
  • Map()
  • Number()
  • Object()
  • Proxy()
  • Promise()
  • RangeError()
  • ReferenceError()
  • RegExp()
  • Set()
  • String()
  • Symbol()
  • SyntaxError()
  • TypeRrror()
  • Uint8Array()
  • Uint8ClampedArray()
  • Uint16Array()
  • Uint32Array()
  • URIError()
  • WeakMap()
  • WeakSet()

 そのほかのグローバルオブジェクト。

  • JSON
  • Math
  • Reflect

 各オブジェクトについての詳細は後の章で説明されている。

ECMAScript 2015の仕様書を読む(その4)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は関数とクラスの解説がある第14章。ここではアロー関数やclassキーワード、関数のデフォルト値、可変長引数など多くの新機能が説明されている。

第14章

 関数とクラスについて。14.1では、以前よりあったfunctionキーワードを使った関数定義が説明されている。functionキーワードでの関数定義では、新たにRest Parameterという仕組みが導入された。これは、下記のように記述することで、可変長引数をより簡単に扱える仕組み。

function 関数名(引数1, 引数2, […,] ...残り引数)

 たとえば以下のようにすると、foo関数に与えた3つめ以上の引数は配列restに格納される。

function foo(arg1, arg2, ...rest) {}

 また、引数では新たにInitializerを使用できる。「引数=値」のように指定することで、その引数がundefinedだった場合、指定した値がセットされる。たとえば次の関数では、2つめの引数がundefinedだった場合、arg2には1が代入される。

function foo(arg1, arg2 = 1) {}

 14.2ではアロー(「=>」)を使った関数定義(アロー関数)が説明されている。アローを使った関数定義は、簡単にまとめると以下のようになる。

() => {関数定義}
(引数1) => {関数定義}
(引数1, 引数2, [...]) => {関数定義}
(引数1, 引数2, [...], ...rest) => {関数定義}

 {関数定義}の代わりに戻り値を直接記述することも可能。たとえば次の関数は、与えた引数の和を返す。

(a, b) => a + b

 なお、アロー関数内ではargumentsやsuper、this、new.targetが定義されず、関数を定義したレキシカル環境のそれぞれをそのまま継承する。

 14.3はメソッド定義についての説明。新たにget/setキーワードが導入されている。メソッド定義の際にメソッド名の前に「get」もしくは「set」を付与することで、getter/setterを定義できる。このメソッドに対しプロパティのように値を代入すると、代入した値を引数として定義したsetter関数が実行される。また、プロパティのように参照すると定義したgetter関数が実行され、その戻り値が返される。なお、getter関数には引数は与えられない。

 14.4は新たに実装されたgenerator関数についての説明。メソッド定義時の際にメソッド名の前に「」を付与することで定義できる。generator関数では、yieldキーワードを使って関数の途中で実行を中断し、そ時点で指定した値を返すことが可能。yieldもしくはyieldキーワードで中断された関数を再度呼び出すと、その続きから実行が再開される。

 14.5ではclassキーワードなどを使ったクラス定義が説明されている。classキーワードもECMAScript2015の新機能。次のようなスタイルでクラスを定義できる。

class クラス名 [extends 継承するクラス名] {
  クラスの定義
}

 クラスの定義では、staticキーワードを使ったメソッドの定義が可能。

 14.6では末尾再帰の最適化についての説明。再帰的に実装されているコードをループに展開する流れに書いてある処理系による実装の話なので、JSコードを書く側としてはあまり意識する必要は無いはず。

ECMAScript 2015の仕様書を読む(その3)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は第12章と第13章。ここではひたすら定義が並んでいるので斜め読みして、必要に応じて戻ることにする。

第12章

 ECMAScriptの式について。deleteやvoid、typeof、instanceofなどを含む演算子の挙動についても解説されている。新キーワードであるyieldも登場。

 yieldはPythonのyieldと同様の処理を行うもので、関数の実行を中断して戻り値を返すというもの。その関数オブジェクトのnextメソッドを実行することで中断したところから実行を再開できる。

第13章

 文と宣言について。新しいキーワードであるletやconst、classなどが登場する。また、新たな構文であるfor〜of文も登場。

 letとconstはvarと同じく変数定義に使うキーワード。letはレキシカルスコープのみで通用する、いわゆる局所変数を定義するのに使い、constは定数として宣言するのに使う。

 また、新たにfor〜of文も登場している。for〜in文と似ているが、プロパティ名ではなくプロパティの値に対して反復処理を行う点が異なる。

ECMAScript 2015の仕様書を読む(その2)

 ECMAScript 2015の仕様書(ECMA-262)を読んでいます。今回は第10章と第11章。第11章ではECMAScript 2015で追加されたテンプレートリテラルについての記述があるほか、細かいコード表記ルールが記載されているので目を通しておくと良い。

第10章

 ECMAScriptのソースコードについて。ソースコードはUnicodeで記述する。Unicodeではさまざまな符号化形式(UTF-8やUTF-16など)があるが、これについては規格では言及されていない。

 ECMAScriptコードが「use strict」ディレクティブで始まると、そのコードはStrictモードコードとして解釈される。また、モジュールコードやクラス宣言などもstrictモードのコードとなる。そのほか、一定の条件を満たすコードはstrictモードのコードとなる。それ以外のコードは非strictモードのコードとなる。

第11章

 ECMAScriptの文法について。

  • タブやVT、FF、スペースなどはすべてホワイトスペースとして扱われる。
  • CR、LF、LS、PSが改行として扱われる。CRとLFが続いた場合、単一の改行として扱われる。
  • コメントには複数行コメント(「/」から「/」で囲まれた部分)と単一行コメント(「//」から行末まで)がある
  • 「識別子」(変数名やメソッド名)は「ID_Start」プロパティを持つ任意のUnicode文字、「$」、「」、「\」+Unicodeのエスケープシーケンスから始まる必要がある。また、利用できる文字は「ID_Continue」プロパティを持つ任意のUnicode文字と「$」、「」、「\」+Unicodeのエスケープシーケンス、(ZERO WIDTH NON-JOINNER、U+200C)、(ZERO WIDTH JOINNER、U+200D)。

 ECMAScriptには予約語があり、これらを識別子として使うことはできない。予約語一覧は以下のとおり。

break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try

 また、次の2つは将来のための予約語(Future Reserved Words)とされており、こちらも利用できない。

enum await

 そのほか、strictモードでは下記も予約語とされている。

implements package protected
interface private public

 そのほか、「null」や「true」「false」も利用できない。

 数値リテラルについては、整数、小数、「e」や「E」を使った10のn乗表記、「0B」「0b」を使った二進数表記、「0o」「0O」を使った8進数表記、「0x」「0X」を使った16進数表記が可能。16進数表記では大文字/小文字の両方が利用可能。

 「"」もしくは「'」で囲んだ文字列は文字列リテラルとなる。どちらも改行を含むことはできない。また、「\」に続く文字はエスケープシーケンスとなる。複数行で記述したい場合、「\」+改行を使う。また、エスケープシーケンスとしては「'」「"」「\」「\b」「\f」「\n」「\r」「\t」「\v」と「\<数値>」、「\x<16進数>」、「\uXXXX」、「\u{XXXX}」が利用できる(XXXXは16進数4文字)。

 「/<正規表現>/<フラグ>」という文字列は正規表現リテラルとなる。正規表現内では「\」、「/」、「[」は使えない。また、正規表現の1文字目に「*」は使えない。改行も使えない。これらを使いたい場合は代わりにエスケープシーケンスを使う。

 「`」で囲まれた文字列はテンプレートリテラルとなる。この機能はES6で新たに実装されたもの。文字列リテラルと異なり、改行を含むことが可能。このとき、CRLF(\r\n)やCR(\r)はLF(\n)に変換される。また、エスケープシーケンスのほか、「${」と「}」でコードを囲むことでその値を文字列に取り込むことができる。

 ECMAScript処理系は必要に応じて自動的にセミコロンを挿入する。自動セミコロン挿入には3つの基本ルールがある。これは積極的に使うべきではないので説明は割愛。

ECMAScript 2015の仕様書を読む(その1)

 ECMAScript 2015の仕様書(ECMA-262)を最近読み始めたので、従来のECMAScript 3/5との差異を中心に各章の要点を軽くまとめていく。

 今回は第1章〜第9章まで。ここではECMAScript処理系の内部実装について説明されており、ECMAScriptを使うだけであれば理解は不要。CでNode.js向けモジュールを実装する場合などは知っておくと良いかもしれない。

第1章

 この文書はECMAScript 2015について定義されているということが書いてある。

第2章

 ECMAScript実装が必要とする要件等が書いてある。

第3章

 関連文書について言及。ECMAScript 2015では国際化機能が実装されており、それは別文書(ECMAScript 2015 Internationalization API Specification)でまとめられている

 また、JSONの仕様はStandard ECMA-404 The JSON Data Interchange Formatでまとめられている。

第4章

 ECMAScriptの概要や歴史が書いてある。オブジェクト指向、プロトタイプベースの敬称といった特徴が説明されている。また、用語についても説明されている。この辺りは以前のECMAScriptから変更はない。

第5章

 このドキュメントにおける表記法が説明されている。

第6章

 ECMAScriptで利用できるデータ型と値の説明。こちらも以前からの変更はなし。数値型は64ビット倍精度浮動小数点とか、2の53乗-2がNaNに割り当てられているとか、Infinity(無限大)が定義されているとかが書かれている。オブジェクトが内部的に実装しているメソッドとかの話もあるが、これらはECMAScriptコードからは隠蔽されているのでECMAScriptコードを書く用途では特に覚えなくてもOK。

第7章

 型変換ルール(ObjectやSymbolはtrueになるとか、Stringは空文字列の場合のみfalseになるとか、文字列を数値に変換するルールとか)やオブジェクト型の判定ルール、2つの値が同一かどうかの比較ルールなどが説明されている。

第8章

 ECMAScriptがどうやってコードを実行するのか、という話。

  • ECMAScriptのレキシカル環境は関数宣言やブロックステートメント、TryステートメントとのCatch節などで開始されるよ
  • どのレキシカル環境にも属さない環境はグローバル環境と呼ばれるよ
  • モジュール環境や関数環境といった環境も存在するよ
  • ECMAScriptのコードは評価前に「Realm」(領域)というものに関連付けられるよ
  • 実行コンテキストというものがあるよ
  • ジョブやジョブキューというものがあるよ
  • 一つの実行コンテキストが終了したら、ジョブキューからジョブを1つ取り出してそこから実行コンテキストを作成するよ

第9章

 オブジェクトの振る舞いの話。すべてのオブジェクトはPrototypeという内部スロットを持ち、これを使ってオブジェクトの継承を実現している。また、Extensibleという内部スロットもあり、これがfalseの場合Prototypeスロットは変更が禁止される。

 関数オブジェクトは「strict function」と「non-strict function」の2種類が存在しうる。どちらもレキシカル環境を内包するほか、基底オブジェクトなのか派生オブジェクトなのかといった情報や、関数の種類(normal、classConstructor、generator)といった情報を内部的に持っている。

 ECMAScriptにはいくつかのビルトイン関数があるが、これらの関数オブジェクトは特殊なビルトイン関数オブジェクトとして定義されている。これらのオブジェクトは通常の関数オブジェクトとは異なり、一部の内部メソッドなどを持たないなどの違いがある。

 特殊なオブジェクトとして、Exoticオブジェクトというものがある。9.4節ではExoticオブジェクトとしてArrayオブジェクトやStringオブジェクト、Intger Indexedオブジェクト、Module Namespaceオブジェクトについて説明されている。Exoticオブジェクトはオブジェクトとしての特性を持ちつつ、特別な特性も実装されている(たとえばArrayオブジェクトであればlengthプロパティを持っていたり、インデックスでのアクセスが可能であったり)。

 さらに、その一部のみがECMAScriptで実装されているProxyオブジェクトというものも存在する。これは、ほかの言語で実装されたコードをECMAScriptコードから呼び出すために使われる。