2016-03-24 89 views
10

我有一個類。我需要在超時時間內完成一些http工作。我面臨的問題是超時內的http變量一直說它是未定義的。setTimeout裏面的變量說明它是未定義的,但是當它在外面定義時

export class MyClass { 

    http:Http: 

    constructor(private http:Http) { 
     this.http = http; 
    } 

    sendFriendRequest(){ 

    this.http.post(...//http variable is defined here 
      setTimeout(function(){ 
       this.http.post(... //http is not defined here 
     } 
    } 
} 
+7

這是因爲'這個'上下文:http://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback – nikoskip

+4

我們真的需要4個答案,這個問題基本上都是這樣說的「使用箭頭函數來獲得正確的'this' context」? –

+3

@MarkRajcok是的,有3個答案是不夠的! –

回答

19

這樣做的原因是,裏面的setTimeout 回調函數是在不同的詞彙環境。這就是爲什麼可以使用=>來定義ES6 +功能的原因。這是爲了使函數中的代碼與函數共享相同的範圍。

爲了解決這個問題,您可以使用ES6 +語法,其中代替function(a,b,args) {...}你可以使用(a,b,args) => {...}

setTimeout(() => { 
    this.http.post(...) 
}); 

或與ES5語法:

var root = this; 

setTimeout(function(){ 
    root.http.post(...) 
} 

希望這有助於!

6

你應該在這裏使用箭頭函數來保存這個。

setTimeout(()=>{ 
    this.http.post(... //http is not defined here 
}) 

在這樣做時,this函數的內部被綁定到外部環境。這是一樣的:

setTimeout(function(){ 
    this.http.post(); 
}.bind(this)); 
2

它不是thissetTimeout同樣,當您使用function(){...

2點最流行的針對此問題的方法:

1)使用額外的變量外存儲「本」

var that = this; 
this.http.post(...//http variable is defined here 
      setTimeout(function(){ 
       that.http.post(... //http is not defined here 
     } 
    } 

2)使用箭頭功能

this.http.post(...//http variable is defined here 
      setTimeout(() => { 
       that.http.post(... //http is not defined here 
     } 
    } 

第一種方法是舊的ES5,你不需要任何編譯器,對於ES6版本(#2),你將需要使用類似babel的東西。

找到更多關於箭頭功能&巴貝爾在這裏:https://babeljs.io/docs/learn-es2015/

+0

感謝您的信息! – user2924127

3

在JavaScript中,this關鍵字用於訪問其中調用函數的context。除非在當前作用域中設置了'use strict'標誌,否則無論是使用.methodName()語法還是使用.methodName()語法調用它們,都始終使用上下文調用JavaScript中的函數。

當一個函數被沒有像這樣的上下文中調用:

myFunction() 

上下文由運行時假定爲全局窗口對象(除非'use strict'標誌被設置,在這種情況下,上下文將是未定義。)

注意:在使用ES6和Babel等轉譯器時,默認情況下會在輸出中設置嚴格模式。

當一個函數的引用保存在一個對象上時,可以使用點語法將對象作爲'this'的上下文來調用該函數。

var myObj = { 
    myFunc: function(){} 
}; 

// myFunc invoked like this, the value of 'this' inside myFunc will be myObj. 
myObj.myFunc(); 

操縱「這個」:

呼叫和應用

您可以隨時通過與.CALL或方法。適用調用它改變功能的情況下。在這種情況下,你有一個匿名函數,它不會被你調用,而是被setTimeout函數調用。因此,您將無法利用.call或.apply的優勢。

綁定

相反,你可以創建一個具有使用.bind方法的自定義上下文一個新的功能。通過在匿名函數上調用.bind(),將返回一個新的函數,該函數將自定義上下文綁定到「this」。這樣,您可以將自定義綁定函數作爲數據傳遞給setTimeout。

setTimeout(function(){ 
    // your code. 
}.bind(this), 1000); 

現在裏面的匿名函數裏'this'關鍵字會被綁定到正確的值。

詞彙 '這個':

在ES6然而,使用箭頭功能大約 '這個' 變化的規則時。如果你使用這個語法,你會看到'this'的上下文將保持與當前範圍內的任何內容相同。

setTimeout(() => { 
    // Hey I can access 'this' in here! 
}, 1000); 

保存參考:

如果你看一下編譯後的輸出從巴別塔,你會看到巴貝爾通過保存引用到「本」與_this1,_this2等等跟蹤上下文。

要使用此方法自己只是聲明瞭一個新的變量(這是通常使用「是」或「自我」),並使用它訪問值的匿名函數裏面,像這樣:

var self = this; 
setTimeout(function(){ 
    self.http.post... 
}); 

希望這有助於。

更多解釋developer.mozilla.org有good article describing the behavior of 'this' inside a functions scope

+0

感謝您的好評! – user2924127

相關問題