|
JavaScript 2.0
コア言語
概念
|
2002/09/04 (Wed)
値は変数に格納したり関数に渡したり関数から返すことのできる実体である。例えば以下のようなものがそうである:
undefinednull5 (数値)true (論理値)"Kilopi" (文字列)[1, 5, false] (要素数3の配列){a:3, b:7} (2つのプロパティをもつオブジェクト)function (x) {return x*x} (関数)String (クラス、関数、型)型 t は3つのものを表す:
集合 S はどの値が型 t の メンバ とみなされるかを示す。値 v が型 t のメンバであるとき v t のように書くことにする。写像 I は値がどのように型 t へ暗黙の型強制可能かを示す。既に S に含まれている各値 v について、写像 I は v を自身に写像しなければならない。写像 E は値がどのように型 t へ明示的型強制可能かを示す。I のドメイン (領域) にある v について、E は I が写像するのと同じように v を写像する。言い換えると、あらゆる暗黙の型強制は明示的型強制でもあるが、その逆は成り立たない。
値は複数の集合のメンバであることもあり、普通、1つ以上の型に属する。従ってある値の型について問い合わせることは通常有用ではない (代わりに値がある型に属するかどうか問い合わせることはあり得る)。値集合が同じで型変換の対応が異なる、2つの異なる型が存在することもある。
一方、変数は特定の型を持つものである。型 t の変数 x を宣言した場合、x に格納される値は全て型 t のメンバであることが保証され、型 t の値は何でも x に代入することができる。また型 t の写像が値 v の暗黙の型強制を規定していれば、v t である v も x に代入することができる。この場合、型強制した値が x に格納される。
あらゆる型が何らかの値集合を表すが、値集合の全てが何らかの型で表されるわけではない (これは論理的な一貫性に求められることである — 値の無限集合は非可算だが、型の無限集合は数は可算である)。
あらゆる型はそれ自体もまた値であり、変数に格納したり、関数に渡したり、関数から返すことができる。
型 a の値集合が型 b の値集合の部分集合であるとき、型 a を型 b の派生型 (部分型) といい、a b のように書く。
派生型は推移的であり、a b 且つ b c であれば a c である。派生型は反射的でもあり a a も成り立つ。また、v t 且つ t s であれば v s である。
全ての値集合を表しているのが Object
型で、全ての型の基底型である。Object 型の変数にはあらゆる値を格納できる。
いかなる値も含まない集合を表しているのが Never
型で、全ての型の派生型である。戻り値が Never 型の関数は値を返すことができない。[訳注:
戻り値が Void 型の関数とは意味が全く異なる。「関数」を参照]
クラスは、オブジェクトとかインスタンスと呼ばれる同類の値を作成するためのテンプレートである。これらインスタンスは普通、共通のメソッドやプロパティのような特色を共有する。
あらゆるクラスは型でもあり値でもある。型として使用される場合、クラスはそのクラスのインスタンスの全集合を表す。
クラス C は基底クラス S から派生 (導出) することができる。これによりクラス C はクラス S の特色を継承できる。C のあらゆるインスタンスは S のインスタンスでもあるがその逆は成り立たない。上記のような派生型が定義された場合、C と S を型と考えるなら暗黙の内に C S となる。
派生という関係は全てのクラスの集合に対して階層的な関係を課す。将来的の方向性としてあり得る事かもしれないが JavaScript 2.0 は現時点で多重継承をサポートしない。仮に多重継承を許容すると、継承関係は全てのクラスの集合に (全順序関係ではなく) 部分的順序関係が発生する。
クラスは主としてメンバの集合を含んでおり、変数、関数などがメンバとなり得る。メンバはインスタンスメンバとグローバルメンバに分けられる。インスタンスメンバはそのクラスのインスタンスのプロパティとなり、グローバルメンバはクラスオブジェクトそのもののプロパティ (クラスプロパティ) となる。1つのクラスは同名のグローバルメンバをただ1つしか持つことができない。
メンバはその動作を修飾する属性を持つことができる。
インスタンス (オブジェクト) はプロパティの集合を持つ。インスタンスは特定のクラスに属し、そのクラスと祖先クラスで定義されたインスタンスメンバをプロパティとして持たなければならない。これらの束縛はインスタンス作成時に行われる。また、この他にインスタンスは動的プロパティを持つこともできる。これはインスタンス作成後、いつでも追加、削除が可能なプロパティである。
明確に指定しない限り、個別に作成されたインスタンスはそれぞれ異なる識別情報を持つ。デフォルトの === 演算子は
2つのインスタンスが異なるものであれば false を返し、同じであれば true を返す
(ただし NaN は例外で、自分自身と比較しても常に等しくない)。
もはや到達不能になったときにガベージコレクトが行われることが実装には求められることだが、インスタンスはその状態を恒久的に保持する。
プロパティは値に対するプロパティ名の実行時束縛である。プロパティの値は変更できるものもある。プロパティには固定プロパティと動的プロパティがある。固定プロパティはクラス定義のメンバとして宣言され、オブジェクト構築時に作成される。動的プロパティはオブジェクト作成後であればいつでもオブジェクトに追加することができる。JavaScript 1.5 のプロパティは全て動的プロパティである。
プロパティは属性を持つことができる。固定プロパティはその属性を相当するメンバから継承する。
プロパティ名は名前空間 N 、識別子 id 、クラス
C から構成され、インスタンスのプロパティを特定する。プロパティ名を完全な形で記述する言語構文は無い。この草案ではプロパティ名は
N::idC という表記で表される。固定プロパティの場合は C
は相当するメンバが定義されているクラスであり、動的プロパティの場合は
C はインスタンスの最終派生クラスである。
インスタンスは1つのプロパティ名に対して1つしかプロパティを持つことはできない。インスタンスは名前空間
N 、名前 id で同じでクラス C が異なる複数のプロパティを持つことができる。このとき最終派生クラス
C のプロパティが他のプロパティをオーバーライドするという。オーバーライドされたプロパティはなおもインスタンス内に存在し、super
演算子を使ってアクセスすることができる。
スコープは以下のような JavaScript ソースコードの区分された各部分の1つを表す。以下の表に示すようにスコープの中にはリージョナルスコープとして区別されるものもある。
| 非終端生成規則 | リージョナルスコープか | 説明 |
|---|---|---|
| Program | yes | プログラムのトップレベル |
| PackageDefinition | yes | package 定義 |
| ClassDefinition | yes | class 定義 |
| FunctionDefinition | yes | function 定義 |
| FunctionExpression | yes | function 式 |
| Block | no* | ブロック (属性付きディレクティブのグループを除く) |
| ForStatement | no* | for 文 |
| CatchClause | no* | try 文の catch 節 |
*これら3つのスコープは次の外側のスコープがクラススコープであるときリージョナルスコープとなる。
スコープは JavaScript のプログラム実行中には変更できない静的なものである (ただし、プログラムが eval
を呼んだ場合は新しい JavaScript ソースコードは既存のスコープを共有するか自身のスコープを作成する)。トップレベルのスコープ
(グローバルスコープ) 以外は必ず他のスコープの内側に含まれている。2つのスコープが重複している場合、一方が他方を完全に内包していなければならない。つまりスコープは階層的である。
スコープ情報は実行時に変数とプロパティの探索と可視性チェックに使用される。
実行フレームは、スコープ中で定義されている全ての限定名と値を対応付ける実行時束縛の集合を持つ。実行フレームはスコープに入る度に新しく作成され、関数クロージャは自身を作成した実行フレームへの参照を持つ。スコープから抜け出し、実行フレームを参照している全てのクロージャがガベージコレクトされた後に、その実行フレームを破棄することが実装に求められることだが、実行フレームはその状態を恒久的に保持する。
実行フレームの束縛には値を変更できるものもある。束縛の値は最初、未初期化状態であり、この状態で束縛を読み取ろうとするとエラーになる。
実行フレームの束縛は動作を修飾するための属性を持つことができる。
限定名は名前空間 N と識別子 id から構成される。この草案では、限定名は
N::id という表記で表される。実行フレームは1つの限定名に対して多くとも1つしか束縛を持つことができない。
名前空間は名前をパラメータ化する。名前空間属性 N はあらゆる名前やプロパティ p
の宣言に結びつけることができ、p へのアクセスを制限する。コード内の他の箇所で p にアクセスするには名前空間で限定した
N::p を使うか、p へのアクセスが置かれるスコープで
use namespace(N) ディレクティブを実行するしかない。C++
とは異なり、名前空間はスコープではなくそれ自身は名前やプロパティを持たない。名前空間は実行フレーム、クラス、オブジェクトに結び付けられたプロパティや名前のアクセス性と可視性を変更するだけである。
名前空間は :: 演算子の第1オペランドとして渡すことのできる値である。
public は宣言時に使われる既定の名前空間である (グローバルスコープには暗黙の use namespace(public)
ディレクティブが置かれている)。パッケージは定義済み無名名前空間 internal を持ち、クラスは定義済み無名名前空間
private を持つ。これらはアクセス制御を可能にする。ユーザ定義名前空間もまた、より柔軟なアクセス制御に使用できる。
|
Waldemar Horwat 最終更新: 2002年9月4日(水) |