スコープとコンテキストを混乱させています。最初の関数は特定の関数に対して固定され(関数によって返され、外部スコープに効果的に注入されない限り)、2番目の関数(特に、this
この関数の内部を参照するものを定義します)は、呼び出されたときに関数に与えられます-call
そして実際にはとで変更することができますapply
。
このことを考慮:
var someObj = function() {
var internalObj = {
nam: 'internal',
doSomething: function() {
console.log('Called from ' + this.name);
}
}
internalObj.doSomething('Internal'); // 1
var someFunc = internalObj.doSomething;
someFunc(); // 2
return {
nam: 'external',
doSomething: internalObj.doSomething
}
}
var x = new someObj();
x.doSomething(); // 3
setTimeout(x.doSomething, 1000); // 4
setTimeout(x.doSomething.bind({nam:'a new one'}), 2000); // 5
JSFiddle。
この例では、メソッド'doSomething'をinternalObj
変数のプロパティとして定義します。これは、このコンストラクター関数のローカルです。の外部でアクセスしようとするとsomeObj
、ReferenceErrorが発生します。
this
メソッドがコンストラクター関数自体(1)で呼び出されると、メソッドのコンテキストオブジェクト( )が参照するように、「内部から呼び出された」ログが記録されますinternalObj
。
このメソッド(その参照)を別のローカル変数に割り当て、そこから呼び出すと(2)、代わりに「undefined」がログに記録されます。スコープは明らかにここでは変更されていませんが、コンテキスト変数は変更されています。現在、グローバルオブジェクトを参照しています。
次に、コンストラクターの結果としてこのメソッドを返します。そして、物事ははるかに興味深いものになり始めます。関数が外部スコープで使用できるようになりました。ただし、(3)と(4)の呼び出しの結果の違いに注意してください。前者はexternal
(ここでのコンテキストオブジェクトはコンストラクターによって作成されたものであるため)私たちに与えますが、後者は再び私たちを返しundefined
ますが構文は同じです。)これは、タイムアウトに送信された関数とイベントハンドラーがコンテキストを「失う」ために発生します。つまりFunction.prototype.bind
、(5)のようにメソッドで修正しない限り、コンテキストが失われます。