【学習ログ】MDN JavaScript チュートリアル (最終回)
はじめに
この記事は、JavaScript チュートリアルの学習ログです。
学習したもの
MDN にある JavaScript のチュートリアルを学習しました。
MDN JavaScript コーナー
┃
┗ チュートリアル
┣ 完全な初心者向け
┃
┣ 中級者向け
┃
┗ 上級者向け
┣ 継承とプロトタイプチェーン
┣ Strict モード(今回の学習箇所)
┣ JavaScript 型付き配列
┣ メモリ管理
┗ 同時実行モデルとイベントループ
概要
チュートリアルで習った事の概要は下記の通りです。
Strict モード
Strict モードの詳細について学習する。
ノート・メモ
ECMAScript 5 の strict モードを JavaScript にオプトインすることによって幾つかの機能を制限します。strict モードは単なるサブセットではありません。strict モードは意図的に、通常モードとは異なる意味を持っています。
strict モードをサポートしないブラウザは、strict モードのコードについてサポートするブラウザとは異なる動作をする可能性がありますので、strict モードに関する側面をサポートするかの機能テストを行わずに strict モードを頼らないでください。
strict モードのコードと非 strict モードのコードは共存できますので、スクリプトを順次 strict モードにオプトインすることができます。
strict モードでは、通常の JavaScript の意味にいくつかの変更を加えます。
第一に strict モードでは、JavaScript でエラーではないが落とし穴になる一部の事柄を、エラーが発生するように変更することで除去します。
第二に strict モードでは、JavaScript エンジンによる最適化処理を困難にする誤りを修正します: strict モードのコードは、非 strict モードの同一コードより高速に実行できることがあります。
第三に strict モードでは、将来の ECMAScript で定義される予定の構文を禁止します。
strict モードはスクリプト全体または個別の関数に適用できます。括弧 {} で括られるブロック構文には適用できません。 そのような場所に適用しようとしても何も起きません。
eval コード、Function コード、イベントハンドラ属性、setTimeout コードに渡す文字列、およびこれらに似たものはスクリプト全体であり、strict モードを呼び出すと期待どおりに動作します。
スクリプト全体で strict モードを呼び出すには、他のいかなる文よりも前に "use strict"; (または 'use strict';) という文をそのまま追加します。
strict モードには注意すべき点があります。それは、競合しないスクリプトをむやみに連結できないことです。
strict モードのスクリプト同士の連結や、非 strict モードのスクリプト同士の連結は問題ありません。strict のスクリプトと非 strict のスクリプトの連結により混在すること (crossing the streams) だけが問題になります。従って、(少なくとも移行期間中は) 関数ごとを基準にして strict モードを有効にすることを推奨します。
関数で strict モードを呼び出すには、関数本体で他のいかなる文よりも前に "use strict"; (または 'use strict';) という文をそのまま追加します。
strict モードでは構文とランタイムの動作の両方に変更を加えます。変更点は主に以下のカテゴリに分類できます。
ミスからエラー (構文エラーまたは実行時エラー) への変更
従来は受け入れていた一部のミスをエラーに変更します。JavaScript は未熟な開発者にも易しいように設計され、またエラーとすべき操作の一部をエラーとして扱いません。strict モードではこれらのミスをエラーとして扱うことで、開発者は気づいて修正するようになります。
strict モードでは、偶発的にグローバル変数を作成できないようにします。代入文で偶発的にグローバル変数を作成せずにエラーを投げます。
strict モードでは、通常のコードで暗黙的に失敗する代入について、例外が発生します。 (書き込み不可のプロパティへの代入、getter のみのプロパティへの代入、拡張不可 オブジェクトへの新規プロパティ割り当て)
strict モードでは、削除できないプロパティを削除しようとするとエラーが発生します。
strict モードでは、オブジェクトリテラル内のプロパティ名はユニークであることを必須にします。プロパティ名の重複が構文エラーになります。
strict モードでは、関数の引数名がユニークであることを必須にします。引数名の重複を構文エラーにします。
strict モードでは、8 進数表記を禁止します。8 進数表記は ECMAScript の仕様に含まれていませんが、すべてのブラウザは 8 進数表記を先頭にゼロを付加することでサポートします。
与えられた名前から特定の変数を算出する方法の単純化
strict モードでは、コード中の変数名と特定の変数定義との対応づけ方法を単純化します。多くのコンパイラの最適化は、変数 X をあの場所に保管している と表現できることに頼ります。
これは JavaScript のコードを最大限に最適化するために重要です。JavaScript ではこのようなコード内の名前と変数定義との基本的な対応づけを、実行時まで行うことができない場合があります。strict モードではこのような事態が起こるケースを取り除くことで、コンパイラが strict モードのコードをより最適化できるようにします。
strict モードでは、with を禁止します。
strict モードでは、eval は新しい変数を周囲のスコープに広めません。
- 関連して、strict モードのコード内で eval(...) という形式で eval 関数を呼び出した場合は、コードは strict モードとして評価されます。コードを明示的に strict モードで呼び出してもよいですが、必須ではありません。従って、strict モードの eval 内にある名前は、eval の結果として評価されない strict モードのコードと同様に動作します。
strict モードでは、単純名の削除を禁止します。strict モードでは delete name を構文エラーにします。
eval および arguments の単純化
strict モードでは arguments および eval の奇妙さを低減します。通常のコードではどちらも不思議な動作がかなりあります: バインドの追加や削除およびバインドする値を変更するための eval や、arguments の添字つきプロパティが名前付き引数の別名になることです。strict モードでは eval および arguments をキーワードとした手当てにより、完全な修正は将来の ECMAScript まで実現しないものの大きな進歩を遂げます。
第一に、eval および arguments という名前に対して言語構文でのバインドや代入を不可にします。
第二に strict モードのコードでは、内部で作成された arguments オブジェクトのプロパティがエイリアスになりません。
第三に、arguments.callee をサポートしません。通常のコードでは、arguments.callee は取り囲んでいる関数を参照します。この使用法は脆弱です。
セキュアな JavaScript 作成の容易化
strict モードにより"セキュアな" JavaScript の記述がより簡単になります。
現在、一部の Web サイトではユーザ向に対し、Web サイトの他のユーザが実行することができる JavaScript を記述する方法を提供しています。ブラウザ上の JavaScript はユーザの個人的な情報にアクセスできることから、そのような JavaScript は禁じられた機能へのアクセスを削除するよう、実行前に部分的に変換する必要があります。
JavaScript の柔軟性は、ランタイムによる多くのチェックなしにこれを行うことを事実上不可能にします。ある言語機能は、ランタイムのチェック実行にかなりパフォーマンスのコストがかかるとして広まっています。
strict モードのいくつかの調整、そしてユーザが投稿した JavaScript が strict モードのコードであることや信頼できる方法で呼び出されることの要求により、ランタイムのチェックの必要性をかなり減らします。
第一に strict モードでは、this として関数に渡された値をオブジェクトへボクシングしません。 (特定の this を指定するために call、apply、bind を使用してください)。自動的なボクシングはパフォーマンス上のコストがあり、しかしブラウザでグローバルオブジェクトを公開することは、"セキュアな" JavaScript 環境へのアクセスを提供するグローバルオブジェクトを制限する必要があるためにセキュリティ上の危険性があります。従って strict モードの関数では、指定された this を変更せずに使用します。
第二に strict モードでは、ECMAScript の一般的な実装である拡張を通して JavaScript のスタックを "渡り歩く" ことができません。
第三に、strict モードの関数での arguments は対応する関数の呼び出し時の変数にアクセスできません。
将来の ECMAScript の進化への事前対処
将来の ECMAScript では新たな構文を導入する予定であるため、ECMAScript 5 の strict モードでは移行を容易にする制限事項を適用します。将来の変更点の基礎が strict モードで禁止されていると、変更が容易になります。
第一に strict モードでは、いくつかの識別子を予約語にします。その対象は implements、interface、let、package、private、protected、public、static、yield です。strict モードでは、これらを変数や引数の名前として使用できません。
第二に strict モードでは、スクリプトのトップレベルまたは関数内にない function 文を禁止します。通常のコードでは、function 文はどこにでも置くことが許されます。これは ES5 の仕様に (ES3 でさえも) 含まれていません! ブラウザにより意味が異なり互換性がない拡張です。
将来の ECMAScript では、おそらくスクリプトのトップレベルや関数内以外での funciton 文に新たな意味を定義します。strict モードではこのような function 文を禁止する ことで将来の ECMAScript の仕様向けの "宣言を取り除きます"。
ブラウザでの strict モード
ブラウザはまだ strict モードを確実に実装していないため、無条件に依存しないでください。 strict モードは意味を変えます。それら変更点を当てにすると、strict モードを実装していないブラウザでミスやエラーが発生する可能性があります。strict モードの使用時は注意を払い、また strict モードに関する機能を実装しているかの機能テストにより strict モードへの信頼を補ってください。
strict モードをサポートするブラウザとしないブラウザでのコードのテスト を行うようにしてください。strict モードをサポートしないブラウザでしかテストを行わない場合、strict モードをサポートするブラウザで問題が起きる可能性が高くなります。これは逆の場合も同じです。
分かった事
- strict モードの呼び出し方、 strict モードがどのような考えに基づいて機能を制限しているのかが、なんとなく分かりました。
分からなかった事
eval の詳細が分からなかったです。
「strict モードのコードでは、内部で作成された arguments オブジェクトのプロパティがエイリアスになりません。」と記載されていた箇所の arguments オブジェクトの詳細が分からなかったです。
arguments.callee の詳細が分からなかったです。
まとめ
strict モードで制限を加えた状態で、コーディングをする事でエラーを抑えたり品質の高いスクリプトを制作する目的があるのかなと感じました。
【追記】
記事投稿後、残りの上級者向けチュートリアルの記事を参照したところ、今の自分には難しすぎる内容であったり、理論・概念的な内容であったりして、残りのチュートリアルを学習するよりも他の書籍やチュートリアルに進んだ方が良いように感じられました。(もちろん重要な内容であることは承知しています。)
その為、急遽今回の投稿で MDN JavaScript チュートリアルの学習を終了とする事にしました。
チュートリアルを学習してみて、それまで知らなかった内容やコードの書き方を知る事が出来て嬉しかったですし、チュートリアルの内容が理解できるようになっていくたびに力がついてきたと実感しました。一方でブラウザ上で動作する部分の理解がまだいまいちな感じもしているので、学習を継続していきたいと思います。
最後までご覧頂きありがとうございました。