2016-11-28 58 views
0

我有一個管理少量請求的類。所以請求被設置爲一個集合。我這樣做是爲了避免編寫冗長的開關/ if語句。在JavaScript中使用函數/類作爲「值」的含義地圖()

// 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) 
    } 

} 

這本身起作用。

我注意到的第一件事是當使用從「服務」獲取地圖到「小部件」時關鍵字「this」改變範圍,使得createlist()變得未定義。但如果我只是做這個沒有綁定它的作品。

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

當使用地圖我需要.bind(this)。不知道爲什麼「這個」改變?當我嘗試測試和模擬服務並監視服務時,會產生這個問題。我從來沒有被調用過間諜。所以我認爲在創建地圖時會發生什麼是綁定創建新功能。所以我不能窺探

spyOn(MockMakeManagerRequest, 'updateEmployee') 

所以我想弄清楚函數本身如何存儲在Map()中。我正在尋找這個集合的技術含義,以及我如何能夠做到這一點,以便我可以實現這個測試。

這實際上是在Angular 2應用程序中使用。但我不認爲這會產生太大的差異,因爲我試圖在Map()中存儲值時測試/測試函數會發生什麼情況。

+0

至少有關:http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback,http://stackoverflow.com/問題/ 3127429/how-do-this-keyword-work,可能我應該使用其中一個(可能是第二個)以重複投票的方式進行。 –

+0

是的,真的,如果你看過'Map'方面,那是第二個方面的重複。但是我會在下面留下社區維基答案以防萬一。 –

回答

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是錯誤的,而不是如何解決這個問題,但在解釋爲什麼這是錯的,這裏有三個選項來解決它:

  1. Function#bind解決了通過創建功能,當被調用時,將this設置爲特定值。

  2. 另一種解決方案是使用箭頭功能包裝:

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

    箭頭功能有他們this由他們怎麼叫設置,他們收盤價超過this就像關閉了一個範圍內的變量。因此,由於我們在對createRequestMap的調用中定義了它們,其中this是我們要使用的對象,因此箭頭關閉了this,我們很好。

  3. 另一種方法是更改​​使用函數引用調用:

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

    這裏,我們明確地說,我們想this是調用req期間。

+0

我很困惑,因爲'makeRequest(data){this.makeManagerRequest.updateEmployee(body) }'有效。但'requestMap.get(data.requestType)(body)'沒有綁定就無法工作。因此它讓我覺得它是如何存儲在Map中的。 – MonteCristo

+0

我會假設第三個選項也會解決茉莉間諜問題嗎? – MonteCristo

+0

@MonteCristo:我沒有用過它,但我會這麼認爲,是的。 –

相關問題