2012-02-28 8 views
10

最近node.jsで悩んでおり、モジュールのグローバルスコープでthisという使用法に関する奇妙な動作に遭遇しました。node.js:グローバルスコープでの 'this'の使い方が混乱しています

thisはグローバルスコープでmodule.exportsはにバインドされています

console.log(this === exports); // -> true 

しかしthisはメソッドスコープでグローバルにバインドされています

(function() { console.log(this === global); })(); // -> true 

これもこの混乱の動作につながる:

this.Foo = "Weird"; 
console.log(Foo); // -> throws undefined 

(function() { this.Bar = "Weird"; })(); 
console.log(Bar); // -> "Weird" 

私は解がt o thisをグローバルスコープで使用せず、代わりにextendsまたはglobalを明示的に使用しますが、これには論理がありますか、またはnode.jsのバグまたは制限ですか?

答えて

1

単純なCommonJSモジュールの実装では、モジュールのグローバルスコープ内でthisをどうすればよいか考える必要がありました。それは仕様によって対処されていません。

また、私はグローバルオブジェクトへのハンドルを取得するthisを使用していた「modulize」に必要なので、私はthisを変更し、私はそれが有用であろうと思ったので、最初はexportsオブジェクトとして設定し、それ以降のfound some codeグローバルオブジェクトに戻って、モジュールコードに対して可能な限り「正常」に近い環境を提供します。

ノードが設定されている(または作者に尋ねる)理由を推測することはできますが、私が推測するのは、それが便利なアイデアのように思えたからです。moduleノードのexportsプロパティをオブジェクトに反映させ、モジュールの実際のexportsに反映させます(この動作も仕様の一部ではありませんが、どちらにも該当しません)。

thisについては、globalを参照してください。他の回答が説明するとおり、それはちょうど方法thisです。それはノード特有の動作ではなく、変わったjavascriptの動作です。

7

これは、thisの値は、常にの関数がどのように呼び出されるかによって決まるということです。

thisは常にグローバルオブジェクト(非厳密モード)またはundefined(ES5厳密)を参照しています。

あなたは「外側」this値にアクセスしたい場合は、あなた自身を

var outerScope = this; 

(function() { outerScope.Bar = "Weird"; })(); 
console.log(Foo); // -> throws undefined 

のように、その機能を実行する前に参照を格納または.bind()に機能スコープを再可能性のいずれか、

(function() { this.Bar = "Weird"; }).bind(this)(); 
のような
+1

グローバルスコープの 'this'が' extended'の代わりに 'global'にバインドされていたのでは、あまり混乱しないでしょうか?私は、グローバルスコープと静的関数スコープで同じ意味を持つことを期待しています。 –

+0

@SelflessCoder:なぜこれが 'exports'オブジェクトに結びついているのか分かりません。しかし、一般的には、グローバルオブジェクトをデータでぶつけないようにすることをお勧めします。したがって、どのような関数コンテキストでも、どのように呼び出されるかによって、異なる 'this'値を持つことができることに留意してください。 – jAndy

+0

jAndyは言うとおり、これは基本的にjavascriptで 'this'がどのように動作するかです。私はそれについての議論を読んでいないが、グローバルスコープで 'this === exports 'を持つことは、ブラウザーのグローバルスコープで' this === window'と類似していると考えられます。 IMOは、グローバルスコープで 'this === global'を持つことは、' this.foo === foo'を意味するので意味がありません。 –

1

これがNode.jsチームの正確な意図であるかどうかわかりませんが、そうでなかった場合は驚くでしょう。この例では、ブラウザの開発コンソール(例:クロム):

var x = function(){console.log(this)} 
a = {} 
a.x = x 
a.xx = function(){x()} 

a.x() 
>> Object 
a.xx() 
>> DOMWindow 
x() 
>> DOMWindow 

コンテキストを指定せずにメソッドを実行するとわかるように、コンテキストはグローバルなものに設定されます。この場合、DOMWindowオブジェクト。

モジュール内にあるとき、コンテキストはモジュールですが、.callまたは.applyまたはobjでコンテキストを指定せずにその中でメソッドを実行します。ローカルコンテキストの代わりにグローバルコンテキストglobalを使用します。module.exports

関連する問題