2016-07-25 2 views
0

私は、静的なクラス(VBではモジュールとも呼ばれるC#)とインスタンスクラス(インスタンス化できるもの)がある.NETの世界から来ています。Javascriptモジュール内の変数は、その外部に表示されますか?

この質問は、私が既に知っているパターンを作り直して、モジュール/静的クラスを作成しようとしているJavascriptについてです。コードは次のとおりです。

var MyModule = { 
    variable1: 0, 
    variable2: 1, 
    method1: function() { 
     //code goes here 
    }, 
    method2: function() { 
     //mode code goes here 
    }, 
    method3: function() { 
     //and some more just to prove the pattern   
    } 
} 

method1(); //error - no such method - ok, good, I expect that 
variable1 = 5; //silently assigns a variable inside MyModule to 5 ? 

名前空間内で宣言されたメソッドは表示されませんが、変数は何故ですか?また、同じスクリプトでも、これらの変数がMyModuleの外部に表示されないようにする方法はありますか?

+0

これは名前空間でもモジュールでもありません。これは普通のJSオブジェクトです。すべてのプロパティが表示されます。私はなぜあなたが 'method1'がエラーを投げると思うのか分かりません - 私はそうは思わない。あなたが提供したJSFiddleではありません。 'variable1 = 5'はオブジェクト内の変数ではなくグローバル変数を割り当てます。 – vlaz

+0

ここに(少し)更新された[JSFiddle](https://jsfiddle.net/xs4y1k19/1/)があります。これは実際にその関数がアクセス可能であることを示しています。脇に置く方法として、適用されないOOの用語があります - JavaScriptには機能があります。 – vlaz

+0

@Vld:はい、そうです、何らかの理由で 'method1'は自分のJSFiddleにエラーを投げません。しかし、プロダクションコードにエラーが出るので、なぜそれを見つけるのにもっと時間を費やす必要があると思います。混乱の一部は、「存在しない変数、未定義変数の使用など」のような 'variable1 = 5'行にエラーが発生するという私の期待でした。 – Neolisk

答えて

2

あなたのモジュールは実際にはリテラルを使用して初期化されたです。いくつかの誤解に取り組むことから始めます。オブジェクトは情報を隠すことはありません.JavaScriptの場合と同じように、JavaScriptにはprivatepublicのスコープはありません。さらに、オブジェクトのプロパティにアクセスする唯一の方法は、あなたがmethod1という変数を取得し、それを実行しようとしているため、これが失敗したことを通じて

method1(); 

にそれらにアクセスすることです。これは存在しないため、エラーです。ただし、となりますが、MyModule.method1()となります。これは、MyModuleが実際のオブジェクトであるためです。 Javaでは、これはObject MyModule = new Object()を持つのと似ています。このように、MyModule.toString()のようなメソッドを呼び出すことができます - 唯一の "慣習的でない"ことは、インスタンスに大文字の名前が付いていることです - JavaとJavaScriptの変数は通常小文字で始まりますが、それを義務付ける。

次に、このラインがあります:

variable1 = 5; //silently assigns a variable inside MyModule to 5 ? 

ライン上のコメントに答えるために - いいえ、それはしていません。上記の行はwindow.variable1 = 5と同じです。あなたが持っているものは「暗黙のグローバル」と呼ばれています。名前はかなり自己記述的ですが、window.foo = 42は明示的にグローバルなfoo = 42です。windowオブジェクトに戻るため、です。ただし、var foo = 42ではなく、グローバルです。varキーワードは、グローバルwindowオブジェクトにアタッチまたは使用されません。 "use strict"ディレクティブを使用すると、暗黙のグローバルに遭遇したときにJavaScriptエンジンがエラーをスローします。

は今、脇これらの誤解で、私は単にごまかすます別のマイナーなものもあるが、それは実際には大きなことだ - MyModule.method1など機能ではなく、方法があります。メソッドは、それが割り当てられているオブジェクトである暗黙の状態を保持するサブルーチンのオブジェクト指向の用語です。しかし、関数は、本質的にオブジェクトに「属していない」フリーフローティング実行可能コードです。この区別はむしろ学術的に見えるかもしれませんが、それは大きな影響を与えます。しかし、私はあなたにこれを信じるように依頼します、これはここでカバーするには広すぎるトピックです。

これは間違っています。どうすればいいですか?まず、スコープ上で、残りの部分に必要なように:

JavaScriptには、グローバルと機能の2つのスコープがあります。ここではまさに、これが何を意味するのかである:

var foo = 42; 

function bar(input) { 
    var foo = input; 
    return foo; 
} 

console.log(bar(5)); //5 
console.log(foo); //42 

我々はfooと呼ばれる、あまりにも変数を持つ - 1を機能ではないの内側。 1つを割り当てることは、他のものを変更しない - 異なるスコープにあるためです。それは、関数の内部で省略された場合は、その後、我々は

var foo = 42; 

function bar(input) { 
    foo = input; 
    return foo; 
} 

console.log(bar(5)); //5 
console.log(foo); //5 

同じものにアクセスすることになるインナーfooは、機能範囲にあることが宣言されていないので、これがあるので、それがアクセス - それはvarキーワードのおかげです外側(そして外側には - window.fooプロパティなし)。

これで十分です。しかし、ここに隠された側面がありますが、それはすぐには明らかではありませんが、だけがの2つのスコープがあります。ここでは、一見したところ、実際に最初のものと同じものだif文の内側に新しいfooプロパティを宣言していても、私はそう

function bar(condition) { 
    var foo = 5; 
    if (condition) { 
     var foo = 42; 
    } 
    return foo; 
} 

console.log(bar(false)); //5 
console.log(bar(true)); //42 

を意味するものです。他の言語のブロックスコープは{ }なので、そこに宣言された変数はそこにとどまります。 JavaScriptでは真実ではありません。見逃しやすいので、注意することが重要です。

今、あなたの問題に。 には、非常に良い説明があります。Todd Mottoも、私が信じるものは、初心者のための良い記事ですが、the Adequately Good postはさらに深くなっていますが、まだアクセス可能です。それらはすべてモジュールパターンをカバーしています。実際には、それらのリソースやウェブ上に多くのモジュールパターンが見つかります。他の言語のpublicprivateに似たものがあります。私はそれを説明しようとしない、私は他の人が私よりもそれを上手くやったと思うので。しかし、私はモジュールが何であるかを簡単に説明します。ここでも、他のリソースでこれをよりよくカバーできます。

モジュールは、クロージャ詳細情報herehere(StackOverflowの中で最も疑問を投げかけた質問の1つ)というJavaScript機能を利用しています。私が言ったことを覚えている、JavaScriptには2つのスコープがある?クロージャは、単純に言えば、機能的なスコープを提供します。あなたは(/* function goes here */)()に囲まれて、あなたのコードと機能を持っているこの簡単に解剖するには

(function() { /* your code goes here */ })() 

:ここではそれがどのように見えるかです。事実上、これは機能を実行するので、のすべてが機能スコープに入れられます。しかし、これは非常に強力で、ここに例があります。

var closure = (function() { 
    var privateVar = "secret"; 
    return { 
     publicVar: 42, 
     getPrivateVar() { return privateVar; } 
    } 
})() 

console.log(closure.publicVar); //42 
console.log(closure.getPrivateVar()); //"secret" 
//let's change this 
closure.publicVar = 5; 
closure.privateVar = "changed"; 

console.log(closure.publicVar); //5 
console.log(closure.getPrivateVar()); //"secret" 

私たちは(私のものに似ている)プライベートフィールドを持っています。ここでも、var privateVarは機能スコープ内で「ボトルアップ」したままで、外部からはアクセスできません。ちなみに、これはModuleパターンの例です。 var closureの代わりに、私はそれをmyModuleと呼ぶことができました。それはむしろ単純化されていますが、ここではより複雑になることはありません。異なるモジュールはすべて、非常に似たようなものになっています。異なる方法でデータを公開するだけです。しかし、コンセプトは似ています。「プライベート」フィールドは内部にあり、「パブリック」フィールドは他の場所からアクセスできます。

これは長いですが、うまくいけば、基本的なことを説明してください。

+0

ちょっと小さな質問 - 'var p = 5'のような関数外の変数を宣言すると、' p = 5'と同じですか? (厳格なことなし)それ以外は、素晴らしい答え、多くの感謝。私は最大25ポイントしか与えられませんが、確かにそれ以上の価値があります。うまくいけば他の人が私を助けてくれます。 :)私はあなたがJSで可能だったとは思っていなかった何かプライベートなバッキングフィールドを持つpublic getプロパティの例を含んでいたことはいいことです。 – Neolisk

+0

@Neolisk - いいえ、あなたが 'var'を使うと、変数は' window'に結び付けられません。これはそこに追加された不要なものを保護するのに便利です。私が明示的に言及していない(まだ使用されていない)ことの1つは、機能スコープ(したがってクロージャー)が外部と同様に何かにアクセスできることです。 'function bar'がある2番目の例を見ると、それは外部変数にアクセスする関数です。したがって、実際にネストされたクロージャを持つことができます。ここで、内部クロージャは外側のクロージャから変数にアクセスできますが、その逆はできません。この種のものは、Javaのネストされたクラスのように機能します。 – vlaz

+0

これは、3つのスコープではなく、2のように思えます。1. window/global(varを使用するのを忘れたか、明示的に使用されたウィンドウ)2. script(関数の外でvarを使用)3. function関数)。ご確認ください。 – Neolisk

0

いつもStack Overflowに関する質問をする前に、I created a JSFiddleを質問に添付してください。いくつかのステップで問題の原因がわかりました。これは実際には頻繁に起こります。しかし、今回は私の所見を一般に公開したいと思います。 JSの達人はすでにこれを知っていると思われますが、経験の浅い開発者がこの情報を参考にしているかもしれません。

I had two instances of variablevariable1MyModuleに属し、他方はwindow(グローバルスコープ)に属する。デバッガでvariable1にカーソルを合わせると、MyModuleの中にあってもデバッガにはグローバル値が表示されます。 Visual Studio 2015のバグのようですが、これはどのように動作するのですか?次に、MyModuleの関数の1つにブレークポイントを設定し、変数に接頭辞thisがある場合、違う値を示していることに気付きました。明らかに、JS構文ではMyModuleの宣言中にthisを置くことはできませんので、Visual StudioでJSデバッガがどのように動作するかを知っておく必要があります。

私の説明にはほとんど意味がない場合は、たとえばC#プロジェクト内のクラス定義の先頭にある変数にカーソルを移動してみてください。デバッグ中のどの時点でも、誰が何を宣言したかにかかわらず、最新の正しい値がそこに表示されます。 IDEの動作の違いは、私の混乱の原因となっています。また、Javascriptは、変数宣言に十分注意していない場合、グローバル変数を作成する傾向があります。

関連する問題