0x0b
js_ver
最終更新:
0x0b
-
view
バージョン
Mozilla(Netscape)
JavaScriptのバージョン | ECMAScript の版 | NN | IE |
1.0 | ECMA-262 初版に基づく | Navigator 2.0 | |
1.1 | JavaScript 1.2 リリース時ECMA-262初版未完成&br互換性未完成-Netscapeは追加機能搭載&br-Unicode を用いた国際化および全プラットフォームにおける同一の動作という 2 つの新機能を追加した。Date オブジェクトなど、プラットフォームに依存していたり、プラットフォーム固有の挙動を用いたりしている | Navigator 3.0 | |
1.2 | ECMA-262 初版と完全互換 | Navigator 4.0-4.05 | |
1.3 | ==と!=を除く ECMA262に一致するように変更 | Navigator 4.06-4.7x | |
1.4 | ECMA-262 初版と完全互換 リリース時3版未完成 |
|1.5|ECMA-262 第 3 版と完全互換|Navigator 6.0
Mozilla(オープンソースのブラウザ)||
Mozilla(オープンソースのブラウザ)||
1.6 | Firefox 1.5、他の Mozilla 1.8 ベースの製品 | ||
1.7 | Firefox 2、他の Mozilla 1.8.1 ベースの製品 | ||
1.8 | Firefox 3、他の Gecko 1.9 ベースの製品 |
ECMA-262 第 2 版は小規模な改訂と初版の仕様のバグ修正
JavaScript1.5
JavaScript バージョン 1.5 では以下の新機能や改良点が盛り込まれています。
ランタイムエラー
ランタイムエラーが例外として報告されるようになっています。
数値の書式の強化
Number.prototype.toExponential、Number.prototype.toFixed および Number.prototype.toPrecision メソッドの導入により、数値の書式が強化されています。Number オブジェクト のページを参照してください。
正規表現の強化
以下のように正規表現が強化されています。
量指定子 (+、*、?、{}) は ? を続けることでスキップ優先を指定することができるようになっています。正規表現パターンの記述 のページの ? の項目を参照してください。
キャプチャする括弧 (x) の代わりにキャプチャしない括弧 (?:x) を使用することができます。キャプチャしない括弧を使用すると、マッチした部分式に対して後方参照ができなくなります。正規表現パターンの記述 のページの (?:x) の項目を参照してください。
肯定的および否定的な先読み表現がサポートされています。どちらもマッチさせた文字列に続くものに依存したマッチの表現です。正規表現パターンの記述 のページの x(?=y) および x(?!y) の項目を参照してください。
m フラグが追加され、複数行に対してもマッチする正規表現を指定できるようになりました。フラグを用いた高度な検索 のページを参照してください。
ある条件下での関数の宣言
if 節の中で関数を宣言できるようになっています。関数の定義 のページを参照してください。
キャプチャする括弧 (x) の代わりにキャプチャしない括弧 (?:x) を使用することができます。キャプチャしない括弧を使用すると、マッチした部分式に対して後方参照ができなくなります。正規表現パターンの記述 のページの (?:x) の項目を参照してください。
肯定的および否定的な先読み表現がサポートされています。どちらもマッチさせた文字列に続くものに依存したマッチの表現です。正規表現パターンの記述 のページの x(?=y) および x(?!y) の項目を参照してください。
m フラグが追加され、複数行に対してもマッチする正規表現を指定できるようになりました。フラグを用いた高度な検索 のページを参照してください。
ある条件下での関数の宣言
if 節の中で関数を宣言できるようになっています。関数の定義 のページを参照してください。
関数式
式の中で関数を宣言できるようになっています。関数の定義 のページを参照してください。
複数の catch 節
try...catch 文における複数の catch 節をサポートしています。catch ブロック のページを参照してください。
ゲッタとセッタ
オブジェクトにゲッタとセッタを追加できるようになっています。この機能は JavaScript の C での実装でのみ利用可能です。ゲッタとセッタの定義 のページを参照してください。
定数
読み取り専用の名前付き定数がサポートされています。この機能は JavaScript の C での実装でのみ利用可能です。定数 のページを参照してください。
JavaScript 1.6
JavaScript 1.6 では次のような新機能が導入されています。E4X、Array の新しいメソッド、そして Array および String の汎用化です。
JavaScript 1.6 は Firefox 1.5 以降でサポートされています。
E4X
ECMAScript for XML (E4X) は JavaScript 内で XML コンテンツを作成したり処理したりする強力な技術です。私たちは、既存の DOM との透過的な統合など、E4X サポートの向上を続けていくつもりですが、XML ベースのウェブアプリケーションの開発者は Firefox 1.5 での E4X サポートの恩恵を受けることができます。
E4X を利用する際も、あなたは標準的な MIME タイプを使用することができます:
<script type="text/javascript">
しかし E4X の文法は、スクリプトを HTML コメント (<!--...-->) 内に埋め込むという、古いブラウザからスクリプトを見えなくするための一般的な方法と衝突する可能性があります。E4X はまた、スクリプトを XML の CDATA セクション (<![CDATA[...]]>) 内に埋め込むという、"<" や ">" という記号を使えるようにするよりモダンな方法 (これは HTML には適用できないので注意) とも衝突する可能性があります。よくわからない文法エラーが生じた場合は MIME タイプに "; e4x=1" を追加してください:
<script type="text/javascript; e4x=1">
拡張機能のスクリプトは常に HTML コメントを E4X リテラルとして扱うことに注意してください。つまり、"e4x=1" が暗黙的に指定されている状態です。
E4X については、Processing XML with E4X で説明されています。
Array の拡張
Array のメソッドが新しく 7 つ追加されました。これらは項目の場所に関するメソッドと反復的なメソッドの 2 つに分類可能です。項目の場所に関するメソッドは:
- indexOf() - 与えられた項目が最初に出現するインデックスを返す。
- lastIndexOf() - 与えられた項目が最後に出現するインデックスを返す。
反復的なメソッドは:
- every() - 配列の各項目において関数を実行し、訪れることのできたすべての項目について関数が true を返した場合に true を返す。
- filter() - 配列の各項目において関数を実行し、関数が true を返した項目全体からなる配列を返す。
- forEach() - 配列の各項目において関数を実行する。
- map() - 配列の各項目において関数を実行し、その結果の配列を返す。
- some() - 配列の各項目において関数を実行し、訪れることのできたどれかの項目について関数が true を返した場合に true を返す。
詳しい情報については、Working with Arrays、もしくは、Nicholas C. Zakas の Mozilla's New Array Methods という記事を参照してください。
Array および String の汎用化
時々、配列のメソッドを文字列に適用したい場合があり、次のようにして、文字列を文字の配列として取り扱うことがあります。例えば、変数 str に含まれる文字がすべて英字であることをチェックするには、次のように書くでしょう:
function isLetter(character) { return (character >= "a" && character <= "z"); } if (Array.prototype.every.call(str, isLetter)) alert("文字列 '" + str + "' は英字のみ含んでいます!");
この記法はかなり無駄が多く、JavaScript 1.6 では汎用的 (generic) な簡易表記が導入されました:
if (Array.every(str, isLetter)) alert("文字列 '" + str + "' は英字のみ含んでいます!");
同様に String のメソッドをどんなオブジェクトにも簡単に適用できます:
var num = 15; alert(String.replace(num, /5/, '2'));
Working with Array-like objects も参照してください。
JavaScript 1.7
この記事は Firefox 2 の新機能について述べています
JavaScript 1.7 はいくつかの新機能、特にジェネレータ (generators) 、イテレータ (iterators) 、配列内包 (array comprehensions) 、let 式 (let expressions) 、および分割代入 (destructuring assignment) を取り入れた言語アップデートです。JavaScript 1.6 のすべての機能も含まれています。
JavaScript 1.7 のサポートは Firefox 2 に導入されました。
JavaScript 1.7 はいくつかの新機能、特にジェネレータ (generators) 、イテレータ (iterators) 、配列内包 (array comprehensions) 、let 式 (let expressions) 、および分割代入 (destructuring assignment) を取り入れた言語アップデートです。JavaScript 1.6 のすべての機能も含まれています。
JavaScript 1.7 のサポートは Firefox 2 に導入されました。
この記事に含まれるコードの例は JavaScript シェルから実験できます。Introduction to the JavaScript shell を読み、シェルのビルド方法と使い方を学んでください。
JavaScript 1.7 を使う
JavaScript 1.7 の一部の新機能を使うためには、JavaScript 1.7 が使いたいという宣言が必要です。HTML または XUL コードでは次のコードを使ってください。
<script type="application/javascript;version=1.7"/>
JavaScript シェルを使うときは、コマンドラインで -version 170 スイッチを使うか、version() 関数を使って使いたいバージョンを設定する必要があります。
version(170);
新しいキーワード "yield" と "let" を使用する必要のある機能は、既存のコードでそれらのキーワードが変数や関数として利用されている恐れがあるため、バージョン 1.7 と宣言しなければ利用できません。新しいキーワードを導入していない機能 (分割代入と配列内包) は、JavaScript のバージョン宣言なしに利用できます。
ジェネレータとイテレータ
繰り返しの (iterative) アルゴリズム (リストの各要素に同じ処理をしたり、同じデータセットに繰り返し計算を行うなど) を含むコードを開発する際、しばしば計算処理の間その値が維持される必要のある状態変数が使われます。伝統的には、繰り返しのアルゴリズムの介在変数を得るにはコールバック関数を使わなくてはなりません。
ジェネレータ
フィボナッチ数を計算するこの繰り返しアルゴリズムについて考えてみましょう:
function do_callback(num) { document.write(num + "<br>\n"); } function fib() { var i = 0, j = 1, n = 0; while (n < 10) { do_callback(i); var t = i; i = j; j += t; n++; } } fib();
このコードはアルゴリズムのそれぞれの繰り返しステップの処理を実行するのにコールバックルーチンを使っています。この場合、それぞれのフィボナッチ数は単純にコンソールに出力されます。
ジェネレータ (generators) およびイテレータ (iterators) は相互に働き、新しく、より良くこれを実行する方法を提供します。ジェネレータを使って書かれたフィボナッチ数ルーチンがどうなっているか見てみましょう:
exam)
exam)
function fib() { var i = 0, j = 1; while (true) { yield i; var t = i; i = j; j += t; } } var g = fib(); for (var i = 0; i < 10; i++) { document.write(g.next() + "<br>\n"); }
yield キーワードを含む関数がジェネレータです。これを呼ぶと、ジェネレータの仮引数は実引数と結び付きますが、本体は実際には評価されません。代わりにジェネレータ・イテレータが返ってきます。ジェネレータ・イテレータの next() メソッドを呼び出すたびに、繰り返しのアルゴリズムが 1 回ずつ実行されます。それぞれのステップでの値は、yield キーワードで指定された値です。yield をアルゴリズムの繰り返しの範囲を示すジェネレータ・イテレータ版の return だと考えましょう。毎回 next() を呼び出すたび、ジェネレータのコードは yield の次の文から再開します。
あなたはジェネレータ・イテレータを、その next() メソッドを繰り返し呼び出すことで、あなたが望んだ結果の状態にたどりつくまで反復させられます。この例では、私たちが欲しいだけの結果を手に入れるまで g.next() を呼び出し続けることで、私たちはどれだけでも多くのフィボナッチ数を得ることができます。
ジェネレータを指定の時点から再開する
一度 next() メソッドを呼び出してジェネレータをスタートさせると、与えた特定の値を最後の yield の結果として扱わせる send() を使うことができます。その際ジェネレータはその次の yield のオペランドを返します。
一度 next() メソッドを呼び出してジェネレータをスタートさせると、与えた特定の値を最後の yield の結果として扱わせる send() を使うことができます。その際ジェネレータはその次の yield のオペランドを返します。
ジェネレータを勝手な時点から始めることはできません。特定の値を send() する前に必ず next() でジェネレータをスタートさせなければなりません。
注: 興味深い点として、send(undefined) を呼び出すことは next() を呼び出すことと等価です。しかし send() を呼び出す際、生まれたてのジェネレータを undefined 以外の値からスタートさせようとすると TypeError 例外を引き起こします。
ジェネレータ中での例外
投げさせたい例外の値を渡して throw() メソッドを呼び出すことで、ジェネレータに強制的に例外を投げさせることができます。この例外はその時点の中断されたジェネレータの文脈から、つまりあたかもその時点で一時停止されている yield が throw value に置き換わったかのように投げられます。
投げさせたい例外の値を渡して throw() メソッドを呼び出すことで、ジェネレータに強制的に例外を投げさせることができます。この例外はその時点の中断されたジェネレータの文脈から、つまりあたかもその時点で一時停止されている yield が throw value に置き換わったかのように投げられます。
もし投げられた例外の処理中に yield に遭遇しなかった場合、その例外は throw() の呼び出し元に伝播し、それ以降 next() を呼び出すと StopIteration が投げられます。
ジェネレータを閉じる
ジェネレータは自分自身を閉じさせる close() メソッドを持っています。ジェネレータを閉じることの効果は:
ジェネレータは自分自身を閉じさせる close() メソッドを持っています。ジェネレータを閉じることの効果は:
ジェネレータ内のアクティブなすべての finally 節が実行されます。
もし finally 節が StopIteration 以外の例外を投げた場合、その例外は close() メソッドの呼び出し元に伝播されます。
ジェネレータが終了します。
もし finally 節が StopIteration 以外の例外を投げた場合、その例外は close() メソッドの呼び出し元に伝播されます。
ジェネレータが終了します。
ジェネレータの例
このコードは 100 回ループするごとに yield するジェネレータを走らせます。
exam)
このコードは 100 回ループするごとに yield するジェネレータを走らせます。
exam)
var gen = generator(); function driveGenerator() { if (gen.next()) { window.setTimeout(driveGenerator, 0); } else { gen.close(); } } function generator() { while (i < something) { /** 何か **/ ++i; /** 100 周ごとに yield **/ if ((i % 100) == 0) { yield true; } } yield false; }
イテレータ
イテレータ (iterator) とは、データへの繰り返しの処理をしやすくする特別なオブジェクトのことです。
普通の使い方では、イテレータオブジェクトは「目に見えません」。つまりあなたはイテレータオブジェクトを明示的に操作する必要はなく、代わりに JavaScript の for...in や for each...in 文を使うことで、オブジェクトのキーや値への繰り返し処理を自然と行うことができます。
exam)
exam)
var objectWithIterator = getObjectSomehow(); for (var i in objectWithIterator) { document.write(objectWithIterator[i] + "<br>\n"); }
もし独自のイテレータオブジェクトを実装したり、イテレータを直接操作する何か別の必要があったりするならば、あなたは next メソッドと StopIteration 例外、そして __iterator__ プロパティについて知る必要があります。
あなたは Iterator(objectname) を呼び出すことで、あるオブジェクトのイテレータを生成することができますが、そのようなあるオブジェクトのイテレータは、そのオブジェクトの __iterator__ メソッドを呼び出すことで見つけられます。もし __iterator__ が存在しなければ、デフォルトのイテレータが生成されます。デフォルトのイテレータは、普通の for...in や for each...in のモデルに基づいて、オブジェクトのプロパティを yield します。もしあなたがカスタマイズしたイテレータを提供したいならば、__iterator__ メソッドをあなたのカスタマイズしたイテレータのインスタンスを返すように上書きしてください。スクリプトからオブジェクトのイテレータを得るには、直接 __iterator__ プロパティにアクセスせず Iterator(obj) を使ってください。後者は配列 (Array) に対しても使えますが、前者は使えません。
一度イテレータを手に入れれば、そのイテレータの next() メソッドを呼び出すことで簡単にオブジェクトの次の項目を取得することができます。もしデータが残っていない場合は、StopIteration 例外が投げられます。
ここに直接的なイテレータ操作の単純な例を示します:
exam)
exam)
var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"}; var it = Iterator(obj); try { while (true) { print(it.next() + "\n"); } } catch (err if err instanceof StopIteration) { print("レコードの終わり。\n"); } catch (err) { print("不明なエラー: " + err.description + "\n"); }
このプログラムの出力は次のようになります:
exam)
exam)
name,Jack Bauer username,JackB id,12345 agency,CTU region,Los Angeles
レコードの終わり。
イテレータを生成する際、オプションとして 2 つ目の引数を指定することができます。この引数は真偽値で、next() メソッドを呼び出すごとにキーの方だけを返してほしいかどうかを示します。このパラメータはユーザー定義の__iterator__ 関数に唯一の引数として渡されます。上のサンプルで var it = Iterator(obj); を var it = Iterator(obj, true); に変えると、以下のような出力になります:
exam)
イテレータを生成する際、オプションとして 2 つ目の引数を指定することができます。この引数は真偽値で、next() メソッドを呼び出すごとにキーの方だけを返してほしいかどうかを示します。このパラメータはユーザー定義の__iterator__ 関数に唯一の引数として渡されます。上のサンプルで var it = Iterator(obj); を var it = Iterator(obj, true); に変えると、以下のような出力になります:
exam)
name username id agency region
レコードの終わり。
どちらの場合でも、データが返ってくる実際の順番はその実装によって変わります。データの順番は無保証です。
どちらの場合でも、データが返ってくる実際の順番はその実装によって変わります。データの順番は無保証です。
イテレータは、その中にあなたが気づいていないデータが含まれているかもしれないオブジェクトも含め、オブジェクト中のデータをスキャンする手軽な方法です。これは特に、アプリケーションが予想していないデータを保存する必要がある場合に便利です。
配列内包
配列内包 (array comprehensions) は、配列のパワフルな初期化を実行する簡便な方法を提供するジェネレータの使い方です。例えば:
exam)
exam)
function range(begin, end) { for (let i = begin; i < end; ++i) { yield i; } }
range() は begin から end までのすべての数値を返すジェネレータです。このように定義すると、私たちはこれを次のように使うことができます:
var ten_squares = [i * i for each (i in range(0, 10))];
これは新しい配列 ten_squares を、0..9 の範囲にある値の平方を含むようあらかじめ初期化します。
これは新しい配列 ten_squares を、0..9 の範囲にある値の平方を含むようあらかじめ初期化します。
あなたは配列を初期化する際、任意の条件文を使うことができます。もしある配列を 0 と 20 の間にある偶数が含まれるように初期化したいならば、次のコードを使うことができます:
var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)];
JavaScript 1.7 以前では、これは次のようにコーディングしなければならないでしょう:
exam)
exam)
var evens = []; for (var i=0; i <= 20; i++) { if (i % 2 == 0) evens.push(i); }
配列内包はより一層コンパクトであるだけでなく、一度そのコンセプトに精通してしまえば、実際のところ読みやすいものです。
スコープの規則
配列内包は暗黙的な let 宣言と同様に、角カッコの内側にあるすべてを含んだその周りに暗黙的なブロックを持ちます。
Add details.
Add details.
let を使ったブロックスコープ
データや関数のブロックスコープを管理する let を使うにはいくつかの方法があります:
データや関数のブロックスコープを管理する let を使うにはいくつかの方法があります:
let 文 は、あるブロックのスコープ内で、ブロックの外にある同じ名前の変数の値に影響を与えることなく、変数と値を関連付ける手段を提供します。
let 式 は、1 つの式だけに対して変数スコープを確立することができます。
let 定義 は、その定義が行われたブロックにスコープが拘束された変数を定義します。この構文は var に対し使われる構文に非常によく似ています。
また、let を使って for ループの文脈内でのみ存在しうる変数を確立することができます。
let 式 は、1 つの式だけに対して変数スコープを確立することができます。
let 定義 は、その定義が行われたブロックにスコープが拘束された変数を定義します。この構文は var に対し使われる構文に非常によく似ています。
また、let を使って for ループの文脈内でのみ存在しうる変数を確立することができます。
let 文
let 文は変数に対するローカルスコープを提供します。let 文はコードのある 1 つのブロックのレキシカルスコープに 0 以上の変数を結びつけることによって働き、それ以外はブロック文と全く同じです。特に、let 文の内側で var を使って定義された変数のスコープは、let 文の外側でそれが定義された場合と同じであり、そのような変数は従来通り関数スコープを持つことに注意してください。
let 文は変数に対するローカルスコープを提供します。let 文はコードのある 1 つのブロックのレキシカルスコープに 0 以上の変数を結びつけることによって働き、それ以外はブロック文と全く同じです。特に、let 文の内側で var を使って定義された変数のスコープは、let 文の外側でそれが定義された場合と同じであり、そのような変数は従来通り関数スコープを持つことに注意してください。
exam)
var x = 5; var y = 0; let (x = x+10, y = 12) { print(x+y + "\n"); } print((x + y) + "\n");
このプログラムからの出力は次のようになるでしょう:
exam)
27 5
コードブロックに関するルールは JavaScript の他のコードブロックと同じです。let 宣言を使って確立されたブロック自身のローカル変数を持っているかもしれません。
注: let 文の構文を使う時、let の後の丸カッコは必須です。これを入れないと構文エラーとなります。
スコープの規則
let を使って定義された変数のスコープは、let ブロック自身とその内部に含まれるすべてのブロックです。ただしそれらのブロックが同じ名前で変数を定義している場合を除きます。
let を使って定義された変数のスコープは、let ブロック自身とその内部に含まれるすべてのブロックです。ただしそれらのブロックが同じ名前で変数を定義している場合を除きます。
let 式
let を使ってある 1 つの式だけに対してスコープを持つ変数を確立することができます:
let を使ってある 1 つの式だけに対してスコープを持つ変数を確立することができます:
var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y + "<br>\n");
document.write(x+y + "<br>\n");
結果として出力されるのは:
var y = 0;
document.write( let(x = x + 10, y = 12) x+y + "<br>\n");
document.write(x+y + "<br>\n");
結果として出力されるのは:
27
5
この場合、変数 x、y のそれぞれ x+10、12 との結び付きは、式 x+y に対してのみスコープを持ちます。
5
この場合、変数 x、y のそれぞれ x+10、12 との結び付きは、式 x+y に対してのみスコープを持ちます。
スコープの規則
以下の let 式があったとすると:
exam)
以下の let 式があったとすると:
exam)
let (decls) expr
expr の周りに暗黙的なブロックが生成されます。
let 定義
let キーワードはブロック内で変数を定義するのにも使うことができます。
let キーワードはブロック内で変数を定義するのにも使うことができます。
注: もしあなたがより興味深い let 定義の使用例を知っているならば、どうぞここに追加することを検討してみてください。
if (x > y) { let gamma = 12.7 + y; i = gamma * x; }
let 文・式・定義はしばしば、内部関数が使われる際にコードを簡潔にさせることがあります。
exam)
exam)
var list = document.getElementById("list"); for (var i = 1; i <= 5; i++) { var item = document.createElement("LI"); item.appendChild(document.createTextNode("Item " + i)); let j = i; item.onclick = function (ev) { alert("Item " + j + " is clicked."); }; list.appendChild(item); }
上の例は、(無名の) 内部関数の 5 つのインスタンスがそれぞれ変数 j の異なる 5 つのインスタンスを参照しているために、意図通りに動きます。もしこれで let を var に置き換えたり、変数 j を削除して単純に i を内部関数で使うと、これは意図通りには動かないことに注意してください。
スコープの規則
let によって宣言された変数は、その定義があったブロックと、その変数が再定義されていないすべてのサブブロックにスコープを持ちます。この場合、let は var に非常によく似た働きをします。おもな違いは var 変数のスコープがそれを囲む関数全体であることです:
exam)
let によって宣言された変数は、その定義があったブロックと、その変数が再定義されていないすべてのサブブロックにスコープを持ちます。この場合、let は var に非常によく似た働きをします。おもな違いは var 変数のスコープがそれを囲む関数全体であることです:
exam)
function varTest() { var x = 31; if (true) { var x = 71; // 同じ変数! alert(x); // 71 } alert(x); // 71 }
function letTest() { let x = 31; if (true) { let x = 71; // 違う変数 alert(x); // 71 } alert(x); // 31 }
= の右辺の式はブロックの内側になります。これは let 式や let 文のスコープの仕方と異なります:
function letTests() { let x = 10;
// let 文 let (x = x + 20) { alert(x); // 30 }
// let 式 alert(let (x = x + 20) x); // 30
// let 定義 { let x = x + 20; // ここでの x は undefined と評価される alert(x); // undefined + 20 ==> NaN } }
プログラムやクラス内では、let は var がするようにグローバルオブジェクトのプロパティを生成したりはせず、代わりにその文脈で文を評価する際に生成される暗黙的なブロックにプロパティを生成します。これが本質的に意味するのは、let はそれ以前に var を使って定義された変数を上書きできないということです。例えば:
FF 2.0 b1 ではうまく動きません。"global" ではなく "42" を返してしまいます。
exam)
var x = 'global'; let x = 42; document.write(this.x + "<br>\n");
このコードによって表示される出力は "42" ではなく、"global" です。
暗黙的なブロック (implicit block) とは、波カッコで囲まれていないブロックのことで、JavaScript エンジンによって暗黙的に生成されます。
関数内で eval() によって実行された let は、var がするように variable object (activation object or innermost binding rib) にプロパティを生成しません。その代りに、そのプログラムで文を評価する際に生成される暗黙的なブロックにプロパティを生成します。これは eval() がプログラムに作用する性質と前述のルールによる結果です。
別の言い方をすれば、コードを実行するのに eval() を使う際、そのコードは独立したプログラムとみなされ、そのコードの周りに暗黙的なブロックを持つのです。
for ループ中での let スコープ変数
let キーワードは単に var でやるようにして、for ループのスコープ内で局所的に変数を結びつけることにも使うことができます。
let キーワードは単に var でやるようにして、for ループのスコープ内で局所的に変数を結びつけることにも使うことができます。
** obj を追加する ** var i=0; for ( let i=i ; i < 10 ; i++ ) document.write(i + "<br>\n");
for ( let [name,value] in obj ) document.write("名前: " + name + ", 値: " + value + "<br>\n");
スコープの規則
for (let expr1; expr2; expr3) statement
この例で、expr2、expr3 と statement は、let expr1 によって宣言されたブロックローカルな変数を含む暗黙的なブロックに囲まれます。これは上の 1 つ目のループで実証しています。
exam)
for (let expr1; expr2; expr3) statement
この例で、expr2、expr3 と statement は、let expr1 によって宣言されたブロックローカルな変数を含む暗黙的なブロックに囲まれます。これは上の 1 つ目のループで実証しています。
exam)
for (let expr1 in expr2) statement for each(let expr1 in expr2) statement
これら両方の場合では、それぞれ statement を含む暗黙的なブロックができます。1 つ目の方は上の 2 つ目のループで示しています。
分割代入
分割代入 (destructuring assignment) は、配列やオブジェクトのリテラルの構造とそっくりの構文を使って、配列やオブジェクトからデータを抽出することを可能にします。
配列やオブジェクトのリテラル式は、データのアドホックな (その場限りの) 詰め合わせを作る簡単な方法を提供します。一度そのようなデータの詰め合わせを作ってしまえば、あなたはそれを使いたいように使うことができます。関数から返すことさえできます。
分割代入を使うと、次の節の例で示すようなさまざまな興味深いことができるようになりますが、特に便利なのは、一つの文によって全体の構造を読み込むことができるという点です。
この能力は Perl や Python などの言語に存在する機能に似ています。
例
分割代入は使用例を通じて説明するのが一番なので、ここではあなたが通読して学ぶためのいくつかの例を紹介します。
分割代入は使用例を通じて説明するのが一番なので、ここではあなたが通読して学ぶためのいくつかの例を紹介します。
一時変数の使用を避ける
分割代入を使えば、例えば値を交換することができます:
exam)
exam)
var a = 1; var b = 3; [a, b] = [b, a];
このコードを実行後、 b は 1 に、a は 3 になります。分割代入がなければ、2 つの値の交換には一時変数 (あるいは一部の低級言語では XOR 交換のトリック) が必要になります。
同様に、3 つ以上の変数を順に交換することにも使えます。
exam)
exam)
var a = 'o'; var b = "<span style='color:green;'>o</span>"; var c = 'o'; var d = 'o'; var e = 'o'; var f = "<span style='color:blue;'>o</span>"; var g = 'o'; var h = 'o'; for (lp=0;lp<40;lp++) {[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a]; document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"<br />");}
このコードを実行すると、変数が循環する様子をカラフルな視覚情報として見ることができます。
上で出てきたフィボナッチ数のジェネレータの例に戻ってみると、"i" と "j" の新しい値を単一のグループ代入文で計算することによって、一時変数 "t" を除去することができます。
exam)
exam)
function fib() { var i = 0, j = 1; while (true) { yield i; [i, j] = [j, i + j]; } } var g = fib(); for (let i = 0; i < 10; i++) print(g.next());
複数の値を返す
分割代入のおかげで、関数は複数の値を返すことができます。関数から配列を返すこと自体はいつでもできたものの、分割代入はさらなる柔軟性を提供します。
exam)
exam)
function f() { return [1, 2]; }
見ての通り、すべての返り値を角カッコで囲んだ、配列に似た構文を使ってその結果を返します。この方法で任意の数の返り値を返すことができます。この例では、f() はその出力として [1, 2] を返します。
exam)
exam)
var a, b; [a, b] = f();
document.write ("A is " + a + " B is " + b + "<br>\n");
[a, b] = f() というコマンドは、関数の返り値を角カッコ中の変数に順番に代入します。a は 1 にセットされ、b は 2 にセットされます。
[a, b] = f() というコマンドは、関数の返り値を角カッコ中の変数に順番に代入します。a は 1 にセットされ、b は 2 にセットされます。
また、返り値を配列として受け取ることもできます。
exam)
exam)
var a = f(); document.write ("A is " + a);
この場合、a は値 1 と 2 を含む配列です。
オブジェクトを横断してループする
オブジェクトからデータを取り出すために、分割代入を使うこともできます:
exam)
exam)
let obj = { width: 3, length: 1.5, color: "orange" }; for (let[name, value] in Iterator(obj)) { document.write ("Name: " + name + ", Value: " + value + "<br>\n"); }
これは、オブジェクト obj の全てのキー/値の組についてループされ、それらの名前と値を表示します。この場合、出力は以下のようになります:
exam)
exam)
Name: width, Value: 3 Name: length, Value: 1.5 Name: color, Value: orange
obj を囲む Iterator() は、JavaScript 1.7 では必須ではありません。しかし、JavaScript 1.8 では必須になるでしょう。これは配列での分割代入を可能にするためです( bug 366941 を参照)。
オブジェクトの配列を横断してループする
それぞれのオブジェクトから興味のあるフィールドだけを取り出しながら、オブジェクトの配列を横断してループすることもできます。
exam)
exam)
var people = [ { name: "Mike Smith", family: { mother: "Jane Smith", father: "Harry Smith", sister: "Samantha Smith" }, age: 35 }, { name: "Tom Jones", family: { mother: "Norah Jones", father: "Richard Jones", brother: "Howard Jones" }, age: 25 } ]; for each (let {name: n, family: { father: f } } in people) { document.write ("Name: " + n + ", Father: " + f + "<br>\n"); }
これは、name フィールドを n に、family.father フィールドを f に抜き出し、それを出力しています。これは people 配列のそれぞれのオブジェクトに対し行われます。出力はこのようになります:
exam)
exam)
Name: Mike Smith, Father: Harry Smith Name: Tom Jones, Father: Richard Jones
一部の返り値を無視する
あなたはまた、興味のない返り値を無視することもできます:
exam)
exam)
function f() { return [1, 2, 3]; } var [a, , b] = f(); document.write ("A is " + a + " B is " + b + "<br>\n");
このコードを実行後、a は 1 になり、b は 3になります。値 2 は無視されます。あなたはこの方法で任意の(あるいは全ての)返り値を無視することができます。例えば:
exam)
exam)
[,,,] = f();
正規表現のマッチから値を取り出す
正規表現の exec() メソッドがマッチを見つけると、正規表現の全体にマッチした部分文字列を 1 つ目の要素に格納し、続いて正規表現内で括弧に囲まれたグループにマッチした部分文字列を順に格納した配列を返します。分割代入を使うと、全体のマッチを使う必要が無ければそれを無視して、配列の一部分のみを取り出すことが簡単にできるようになります。
exam)
exam)
// http / https / ftp 形式の URL にマッチする単純な正規表現 var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url); if (!parsedURL) return null; var [, protocol, fullhost, fullpath] = parsedURL;
JavaScript 1.8
この記事は Firefox 3 の新機能について述べています
JavaScript 1.8 は(Firefox 3 に組み込まれている) Gecko 1.9 の一部分です。これは JavaScript 1.7 よりは大きな更新ではありませんが、ECMAScript 4/JavaScript 2 の進歩に追随するための更新がいくつか含まれています。このリリースは JavaScript 1.6 および JavaScript 1.7 で仕様化された新機能の全てを含んでいます。
JavaScript 1.8 の開発状況を追うためには、 bug 380236 を参照してください。この文書の地位については bug 421027 を参照してください。
JavaScript 1.8 は(Firefox 3 に組み込まれている) Gecko 1.9 の一部分です。これは JavaScript 1.7 よりは大きな更新ではありませんが、ECMAScript 4/JavaScript 2 の進歩に追随するための更新がいくつか含まれています。このリリースは JavaScript 1.6 および JavaScript 1.7 で仕様化された新機能の全てを含んでいます。
JavaScript 1.8 の開発状況を追うためには、 bug 380236 を参照してください。この文書の地位については bug 421027 を参照してください。
JavaScript 1.8 の使用
JavaScript 1.8 のいくつかの新機能を HTML で使用するためには、以下のようにしてください:
<script type="application/javascript;version=1.8"> ... あなたのコード ... </script>
もう 1 つの(推奨されない)方法として、<script> の非推奨の language 属性を使い、"JavaScript1.8" と定義することでもできます。
JavaScript shell や JavaScript XPCOM コンポーネント、XUL の <script> 要素を使うときは、JS の最新バージョン(Mozilla 1.9 では JS1.8)が自動的に使われます( bug 381031 , bug 385159 )。
新たなキーワードである "yield" と "let" を使う必要がある機能は、バージョン 1.7 以上を指定しなければなりません。 なぜなら、既存のコードがそれらのキーワードを変数や関数の名前として使っているかもしれないからです。新しいキーワードを導入していない機能(例えばジェネレータ式)は、JavaScript のバージョンを指定することなく使うことができます。
式クロージャ
この追加機能は、典型的な ラムダ記法(日本語版)に似た表現を与える、単純な関数を書くための簡略表現に過ぎません。
JavaScript 1.7 以前:
exam)
exam)
function(x) { return x * x; } JavaScript 1.8: function(x) x * x
この構文を使うことによって、中括弧と 'return' 文を省くことができます(それらは暗黙的に補われます)。この方式でコードを書くことには、コードを構文的に短くするメリットしかありません。
例:
イベントリスナーを渡す簡略表現:
exam)
イベントリスナーを渡す簡略表現:
exam)
document.addEventListener("click", function() false, true); JavaScript 1.6 からの array のメソッドである some とともにこの記法を使うと:
exam)
elems.some(function(elem) elem.type == "text");
ジェネレータ式
この追加により、ジェネレータ(JavaScript 1.7 で導入されたものです)を簡単に作成することが可能になります。ジェネレータを生成するには、通常は内部に yield を含むカスタム関数を作成しなければなりませんでしたが、この追加により、配列内包に似た構文を使って同じ性質のジェネレータ文を作成することができるようになります。
JavaScript 1.7 では、あるオブジェクトのためのカスタムジェネレータを作成するために、以下のようなものを書くことでしょう:
exam)
exam)
function add3(obj) { for ( let i in obj ) yield i + 3; } let it = add3(someObj); try { while (true) { document.write(it.next() + "<br>\n"); } } catch (err if err instanceof StopIteration) { document.write("End of record.<br>\n"); }
JavaScript 1.8 では、ジェネレータ式を代わりに使うことで、カスタムジェネレータ関数を作成する必要性が無くなります:
let it = (i + 3 for (i in someObj)); try { while (true) { document.write(it.next() + "<br>\n"); } } catch (err if err instanceof StopIteration) { document.write("End of record.<br>\n"); }
ジェネレータ式は、関数に値として渡すこともできます。これは、配列があらかじめ生成される典型的な配列内包の場合と違って、本当に必要とされるまでジェネレータが実行されないので、特に注目に値します。その違いの例を挙げます:
JavaScript 1.7 の配列内包を使った場合
exam)
exam)
handleResults([ i for ( i in obj ) if ( i > 3 ) ]); function handleResults( results ) { for ( let i in results ) // ... }
JavaScript 1.8 のジェネレータ式を使った場合
exam)
exam)
handleResults( i for ( i in obj ) if ( i > 3 ) ); function handleResults( results ) { for ( let i in results ) // ... }
この 2 つの例の大きな違いは、配列内包を使った場合には配列を内包するときと繰り返し処理を行うときの 2 度 "obj" 構造に対してループが実行されるのに対して、ジェネレータ式を使った場合には 1 度しかループが実行されずに済むという点です。
さらなる Array の拡張
JavaScript 1.8 では、 Array オブジェクトに 2 つの新しい繰り返しのメソッドが導入されました:
- reduce() - 配列の全ての要素に関数を実行し、直前の呼び出しから結果を収集します。
- reduceRight() - 配列の全ての要素に関数を実行し、直前の呼び出しから結果を収集しますが、逆から実行します。
for..in の分配方法の変更
JavaScript 1.8 のリリースで生じた変更に、JavaScript 1.7 で導入