2016-11-28 2 views
0

私は、ほとんど要求を管理しないクラスがあります。したがって、リクエストはコレクションとして設定されます。私はこの方法で長いswitch/if else文を書く必要がなくなりました。Javascript Map()の "value"としてfunction/classを使用することの意義

// Manager class 
class makeManagerRequests() { 
    private list = []; 
    private createList(body) { 
    this.list.push(body) 
    } 
    createEmployee(body) { 
    this.createlist(body); 
    } 
    updateManager(body); 
    deleteManager(body); 
} 

// Employee class 
class makeEmployeeRequests() { 

    private list = []; 
    private createList(body) { 
    this.list.push(body) 
    } 
    createEmployee(body) { 
    this.createlist(body); 
    } 
    updateEmployee(body) 
    deleteEmployee(body) 
} 

// Usage in a generic widget 
class makeRequests() { 

    requestMap = new Map(); 

    constructor(makeManagerRequests, makeEmployeeRequests) { 

    } 

    createRequestMap() { 
    requestMap.set('createManager', this.makeManagerRequest.createManager.bind(this)); 
    requestMap.set('updateManager', this.makeManagerRequest.updateManager.bind(this)); 
    requestMap.set('deleteManager', this.makeManagerRequest.deleteManager.bind(this)); 
    requestMap.set('createEmployee', this.makeManagerRequest.createEmployee.bind(this)); 
    requestMap.set('updateEmployee', this.makeManagerRequest.updateEmployee.bind(this)); 
    requestMap.set('deleteEmployee', this.makeManagerRequest.deleteEmployee.bind(this)); 
    } 

    makeRequest(data) { 
    let req = requestMap.get(data.requestType); 
    req(data.body) 
    } 

} 

これ自体は機能します。

「サービス」から「ウィジェット」へのマップを使用するとcreatelist()が定義されなくなるようにキーワード「this」の変更範囲が見つかった。しかし、私はバインドせずにこれを行うだけで動作します。

// I can test this with mocking the makeManagerRequest 
    makeRequest(data) { 
    this.makeManagerRequest.updateEmployee(body)   
    } 

私は.bind(this)が必要です。なぜ "これ"の変化がわからないのですか?この問題は、私がサービスをテストし模擬しようとしているときに発生します。私はスパイが呼び出されたことはありません。だから私はバインドマップを作成するときに新しい機能を作成すると思います。だから私はスパイできません

spyOn(MockMakeManagerRequest, 'updateEmployee') 

私はどのように関数自体がMap()に格納されているかを調べようとしています。私はこのコレクションに技術的な意味合いを探しています。この作業をどのようにして行うことができるので、私はこれを中心にテストを実装できます。

これは実際に角度2アプリで使用されています。しかし、私はMap()の値として格納されたときに何が起こるか/テスト関数をテストしようとしているので、大きな違いはないと思う。

+0

少なくとも関連する:http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback、http://stackoverflow.com/質問/ 3127429/how-does-the-this-keyword-work、おそらく私はこれらのうちの1つ(おそらく2番目の)を重複した投票で使うべきでした。 –

+0

ええ、本当に、もしあなたが 'Map'の面を見ていれば、それはその2番目のものの複製です。しかし、有用な場合に備えて、私は以下のコミュニティwikiの回答を残しておきます。 –

答えて

0

Mapに格納されているものは機能の参照です。 thisの問題は、Map(機能参照を使用していることを除いて)とは関係がありません。それは関数とthisがJavaScriptでどのように機能するかの問題です。のは、単純な例を見てみましょう:

class Example { 
 
    constructor(message) { 
 
    this.message = message; 
 
    } 
 
    method() { 
 
    console.log(this.message); 
 
    } 
 
} 
 
const c = new Example("Hi"); 
 
c.method(); // "Hi" 
 
const f = c.method; 
 
f();  // Error: Cannot read property 'message' of undefined

methodが呼び出されると、それはthisが何であるかを決定することがと呼ばれていますかです:そして、私たちはcからそれを取得する式を使用して、それを呼び出す場合thisの呼び出し中にはcの値を持ちます。しかし、もしそうでなければ、通常はそうではありません。他の価値があります。

私はthisが間違っている、いない、それを解決する方法が、それは間違っている理由を説明した、ここでそれを解決するための3つのオプションである理由あなたが求めていた実現:

  1. Function#bindがその関数を作成することであることを解決します呼び出したときに、thisを指定して元の値を呼び出します。 が自分this彼らは呼ばれている方法によって設定された、彼らは近いthis以上のわずか閉めるようがありません

    requestMap.set('createManager', (...args) => this.makeManagerRequest.createManager(...args)); 
    

    アロー機能:

  2. 別の解決策は、ラッパーとしての矢印の機能を使用することですスコープ内変数。したがって、createRequestMapへの呼び出しの中で定義しているので、使用するオブジェクトはthisです。矢印は、thisをクローズしています。

  3. 別のオプションは、関数のリファレンスを使用して、コール変更することです:そこ

    makeRequest(data) { 
        let req = requestMap.get(data.requestType); 
        req.call(this, data.body); 
    // --^^^^^^^^^^^^ 
    } 
    

    を、我々は明示的に、我々はthisreqの呼び出し中になりたいものを言っています。

+0

'makeRequest(data){ this.makeManagerRequest.updateEmployee(body) }'がうまく動作しないので、私は混乱していました。しかし、 'requestMap.get(data.requestType)(body)'はバインドなしでは動作しませんでした。それで、それは私がマップ内にどのように格納されているかと何かを考えさせました。 – MonteCristo

+0

私は3番目のオプションもジャスミンスパイの問題を解決すると思いますか? – MonteCristo

+0

@MonteCristo:私はそれを使用していないが、私はそう思うだろう、はい。 –

関連する問題