どこでもリンク
JavaScriptの変数は、メモリのどこかに保存されている値を指す単なる名前です。 これらの値は、プリミティブ(文字列、整数、ブール値)、またはオブジェクトまたは関数のいずれかです。
ローカル変数
次の例では、最高レベルのスコープ内に 4つのローカル変数を作成し、いくつかのプリミティブ値をポイントします。
// var name = "Tim Caswell"; var age = 28; var isProgrammer = true; var likesJavaScript = true; // , isProgrammer === likesJavaScript;
出力
=> true
2つの変数がメモリ内の同じ値を指していることに注意してください。 これは、プリミティブが不変であり、仮想マシンがこの値を指すすべての変数参照に対してオブジェクトの1つのインスタンスを使用できるためです。
上記の例では、 ===演算子を使用して2つのリンクが同じ値を指しているかどうかを確認し、 trueの確認を受け取りました。
図の左側の長方形は、トップレベルの外部の閉じたスコープ( Closure Scope )です。 その中の変数は最高レベルのローカル変数です。それらをグローバル/ウィンドウオブジェクトのプロパティと混同しないことが重要です。
オブジェクトとプロトタイプチェーン
オブジェクトは、他のオブジェクトおよびプロトタイプへのリンクの単なるコレクションです。 唯一の違いは、ローカルオブジェクトではなく親にあるプロパティにアクセスするためのプロトタイプチェーンの追加です。
// var tim = { name: "Tim Caswell", age: 28, isProgrammer: true, likesJavaScript: true } // var jack = Object.create(tim); // jack.name = "Jack Caswell"; jack.age = 4; // - jack.likesJavaScript;
出力
=> true
ここでは、 tim変数が参照する4つのプロパティを持つ1つのオブジェクトがあります。 また、最初のオブジェクトを継承し、 jack変数でそれを参照する新しいオブジェクトを作成しました。 その後、ローカルオブジェクトの2つのプロパティを書き換えます。
ここで、 jack.likesJavaScriptプロパティの検索を開始すると、 jackが指すオブジェクトを最初に見つけます。 次に、 likesJavaScriptプロパティを探します。 そこにないので、親オブジェクトを調べてそこを見つけ、このプロパティが参照する真の値を取得します 。
グローバルオブジェクト
jslintのようなツールが常に変数宣言の前にvar式を置くことを忘れないように勧める理由を疑問に思ったなら、これはそうでなければ起こることです:
var name = "Tim Caswell"; var age = 28; var isProgrammer = true; // var likesJavaScript = true;
likesJavaScriptは 、外部の閉じたスコープ内の自由変数ではなく、グローバルオブジェクトのプロパティになりました。 これは、複数のスクリプトを混在させる場合にのみ重要です。 しかし、実際のプログラムでは、これがまさにあなたがやろうとしていることです。
覚えておいてください:常に変数式を入れて、変数を現在および子の閉じたスコープ内に保持してください。
グローバルオブジェクトに何かを配置する必要がある場合は、ブラウザのwindow.wooまたはnode.jsのglobal.wooを使用して意図的に実行します
機能とスコープ
JavaScriptは、関連するデータ構造の単なるコレクションではありません。 関数と呼ばれるコードと呼ばれる実行可能ファイルが含まれています。 関数は、可視性と閉鎖の関連領域を作成します。
障害の視覚化
関数は、プロパティだけでなく実行可能コードも含む特別なオブジェクトとして表すことができます。 各関数には、宣言時に関数が配置された環境を表す特別なプロパティ[スコープ]があります。 関数が別の関数から返された場合、その関数が返された場所から環境へのリンクは、新しい関数によって「閉じ」て「閉じ」ます。
この例では、クロージャを生成して関数を返す単純なファクトリメソッドを作成します。
function makeClosure(name) { return function () { return name; }; } var description1 = makeClosure("Cloe the Closure"); var description2 = makeClosure("Albert the Awesome"); console.log(description1()); console.log(description2());
出力
Cloe the Closureアルバート・ザ・オーサム
description1()を呼び出すと、仮想マシンはこのリンクで関数を探して実行します。 この関数は、 nameというローカル変数を検索し、閉じたスコープ内でそれを見つけます。 このファクトリメソッドは、生成された各関数にローカル変数の独自のスコープがあるという点で優れています。
クロージャーについて詳しく知りたい場合は、私の記事でクロージャーを使用する理由を参照してください(興味がある場合は、この記事も翻訳します)。
共通機能とこれ
生産性やプログラミングスタイルの好みの理由で、 共有 キーワードが使用され、 thisキーワードを使用して異なるスコープで同じ関数を使用できる場合があります。
共通の機能を共有するいくつかのオブジェクトを作成します。 この関数は、 これへのポインターを使用して違いを示します。
var Lane = { name: "Lane the Lambda", description: function () { return this.name; } }; var description = Lane.description; var Fred = { description: Lane.description, name: "Fred the Functor" }; // console.log(Lane.description()); console.log(Fred.description()); console.log(description()); console.log(description.call({ name: "Zed the Zetabyte" }));
出力
レーン・ザ・ラムダフレッド・ザ・ファンクターundefined Zed the Zetabyte
この図では、 Fred.descriptionがLane.descriptionに割り当てられていますが 、これは単なる関数参照であることがわかります。 したがって、3つのリンクはすべて、1つの共通の匿名関数を指します。 そのため、プロトタイプコンストラクターの関数に「メソッド」という名前を付けないようにしています。コンストラクターとその「クラス」への関数のバインドについて誤解を招く可能性があります。
これについてもっと知りたい場合は、私の記事でこれが何であるかを見てください(おおよそ。もし興味があれば、この記事も翻訳します)。
おわりに
これがJavaScript学習者が言語のセマンティクスをよりよく理解するのに役立つことを願っています。 過去には、クライアント開発者/デザイナーであり、サーバーアーキテクトでもあったため、特別な視覚的説明を選択しました。
Tim Caswellによるオリジナル記事: howtonode.org/object-graphs
翻訳者から:これはHabréに関する私の最初の記事および翻訳であり、記事の全サイクルは私にとって非常に有用であると思われました。 著者には、 howtonode.orgにさらに2つのパートと他の多くの資料があります。 不正確または訂正がある場合、私はそれを訂正します。 翻訳のクロージャー(クロージャー)とスコープ(スペース)が正しいかどうかはよくわかりませんが、誰かがもっと良いバージョンを持っているかもしれません。 興味深い場合は、残りの2つの部分を翻訳します。
UPD:タイプミスを修正し、コード例を整理し、ilya42のアドバイスに従って、「スペース」をより正確な「スコープ」 に置き換えました。