2012-07-09 10 views
7

私はまだjs oopで私を悩ます問題があります - 私はそれをやっていると確信していますが、私はそれを正しく行う方法を取得できません。Javascript OOP - 非同期コールバックでこれを失った

例えば、私はこのコード

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

を持っている問題は、私は「request.onloadend」機能のコンテキストからsetTokenに機能するようにアクセスカントということである - 私は「この」への参照を失ったので、そのおそらく。

この問題の解決方法を教えてください。どういうわけかこの関数のコンテキストに "this" varを渡すことはできますか?

ありがとうございます!あなただけの外側のスコープで、それへの参照をキャプチャすることができます

答えて

4

がいくつかありますこれを行う方法。最も直接的には、単にあなたが必要とする値のコピーを保存することです:

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var self = this; // save "this" value 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); // use saved "this" value 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

もう一つの方法は、bindを使用することです:

request.onloadend = (function() { 
    var response = JSON.parse(request.responseText); 

    console.log(response); 
    if(response.result == 'found') { 
    var token = response.token; 

    this.setToken(token); // use saved "this" value 
    this.isSigned = true; 
    } else { 
    console.log('Not logged yet.'); 
    } 
}).bind(this); 

第二のアプローチは、「クリーン」であるが、それは、ブラウザの互換性の問題を持っています(IE < 9はサポートしていません)。コールバックの前に

+0

私はもう一方がより直接的だと思います。コードは最小限に変更され、使用する疑似キーワードを決める必要はありません。ただ言って。 – Esailija

+0

@Esailija:私もそうですが、悲しいことに、その実用的価値はブラウザの互換性によって制約されます。 – Jon

+0

'XHR.onloaded'との間違った点 – Esailija

1

、私は識別子selfを使用しました、しかし名前に多くの意味論的な意味を与えること自由に感じなさい:

var self = this; 
request.onloadend = function() { 
    ... 
    self.setToken(token); 
    ... 
}; 
1

キャプチャthis

Auth.prototype.auth = function() { 
    var self = this; 

    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
2

.bind機能:コールバック外部ローカルVarの

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    }.bind(this); //<-- bound 
} 
0

保存this

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var _this = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     _this.setToken(token); 
     _this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
0

あなたは全く正しいです:コールバックは、コンテキスト(thisのすなわち値)としてXMLHTTPRequestオブジェクトと呼ばれています。あなたは、コールバックの範囲内でそれにアクセスできるように、あなたのインスタンスに別の名前を付ける必要があります。

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(), 
     authInstance = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     authInstance.setToken(token); 
     authInstance.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

See this answer to another question for more explanation of why this is necessary。私はselfではなくauthInstanceを使用しました。なぜなら、記述的な変数名を使用するのが一般的には良いと思うからです。将来の誰か(おそらくあなた!)がコードを読むとき、selfはあいまいかもしれませんが、authInstanceが意味するものを決して解明する必要はありません。

もう1つの選択肢はbindですが、ここで必要以上に複雑になる可能性があります。

+0

ほとんどのコードを修正し、2つの別々の"キーワード "と余分な変数を使うことは、単純に' .bind(this) 'を終わり? – Esailija

+0

@Esailija「バインド」形式は、直感的でわかりやすいと思います。コンテキストは関数の終わりにのみ明確になり、関数はかなり長くなります。それが2行の関数であれば、私はあなたに同意するでしょう。 – lonesomeday

+0

クラスの現在のインスタンス([バインディングの実装方法に関係なく])(http://en.wikipedia.org/wiki/Dynamic_dispatch)を参照しているクラス 'this 'の中で、私の意見では直感的です。しかし、我々はそれに同意できない。 – Esailija

関連する問題