2014-06-05 15 views
3

是否有可能創建一個Array.forEach的替代方法,它自動將上下文「this」設置爲與調用方法時相同的上下文?修改Array.forEach以自動設置上下文作爲調用者

例如(不工作,不知道爲什麼):

Array.prototype.each = function(fn) { 
    return this.forEach(fn, arguments.callee.caller); 
} 


function myFunction() { 
    this.myVar = 'myVar'; 

    [1,2,3].each(function() { 
     console.log(this.myVar); // logs 'myVar' 
    }); 
} 
+0

你爲什麼要這麼做?看起來像一個XY問題... – elclanrs

+0

所以我不必記得綁定或通過「this」每次我循環一個數組 –

+1

答案顯然是「否」,JavaScript函數無法確定'這在調用者。這就是爲什麼'Function.bind()'和箭頭函數存在的原因。 –

回答

4

答案是否定的,一個JavaScript函數無法確定的this在調用方的值。

您可以綁定與當前對象傳遞的功能,這樣

function myFunction() { 
    this.myVar = 'myVar'; 

    [1,2,3].forEach(function() { 
     console.log(this.myVar); // logs 'myVar' 
    }.bind(this)); 
} 

在ECMA腳本6,你可以使用一個Arrow function,這樣

[1,2,3].forEach(() => { 
    console.log(this.myVar); // logs 'myVar' 
}); 
+0

啊,這是目前的方式,我期待它自動,所以我不需要調用.bind(this) –

+1

@Kirk我包括一種使用箭頭函數的方式,請檢查。但是我們需要ES 6的實現。 – thefourtheye

+0

將你的代碼寫入'typescript'並自動獲得胖箭頭功能(包括綁定)。 https://typescript.codeplex.com/。 –

9

Array.forEach已經花費上下文參數作爲可選的最後一個參數,

(function() { 
    this.myvar = "myvar"; 

    [1,2,3,4].forEach(function(v) { 
     console.log("v:"+v); 
     console.log("myvar="+this.myvar); 
    }, this); 
})(); 

請參閱MDN forEach

而且,上面的例子中(如果我們不與方法上關於this情況下處理)工作,而無需使用bindforEach可選的上下文參數,下面還可以正常工作:

function myFunction() { 
    this.myVar = 'myVar'; 

    [1,2,3].forEach(function() { 
     console.log(this.myVar); // logs 'myVar' 
    }); 
} 
myFunction(); 

因爲javascript在功能上有作用,因此匿名函數可以使用this訪問父函數的作用域,並且它可以正確記錄。 this只有在處理實例方法時纔會真正成爲問題。

+0

啊是的,我試圖讓這個自動化,所以我不需要傳入「this」作爲第二個參數 –

+1

然後,根據你以前的例子,如果你在我的例子中添加了'this',它仍然會正確記錄'myvar',因爲你正在調用它的上下文。記住,javascript是函數作用域的,所以傳遞給'forEach'的匿名函數已經可以訪問它的父範圍,由'this'定義功能。處理處理實例的方法時,'this'變量只會成爲問題;但在上述情況下,它只是函數調用和範圍界定。 –

1

另一種繞過回調時與this變量搞亂,你總是可以只分配this到一個新的變量,這樣子範圍的功能,可以訪問:

Array.prototype.each = function(fn) { 
    return this.forEach(fn, arguments.callee.caller); 
} 


function myFunction() { 
    var me = this; 
    me.myVar = 'myVar'; 

    [1,2,3].each(function() { 
     console.log(me.myVar); // logs 'myVar' 
    }); 
} 

現在你不必記住作爲第二參數通過this

0

首先,必須指出,myFunction構造函數。然而,標識符中的第一個字母不是大寫。請撥打MyFunction

如果在沒有new運算符的情況下調用構造函數,則將this綁定到瀏覽器中的全局對象,即window。這使得大寫公約成爲我們發現這種事故的唯一途徑。

的下面幾行代碼演示了此:

// After the original code... 
myFunction(); 
console.log(window.myVar); // logs "myVar" 

其次,要能任意陣列上應用,而不是改變Array.prototype功能,考慮以下因素:

var utils = {array: {}}; // utils.array is a container for array utilities. 
utils.array.each = function (array, func) { 
    var i; 
    for (i = 0; i < array.length; i += 1) { func(array[i]); } 
}; 
utils.write = function (s) { 
    console.log(s); // Alternatively, document.write(s); 
}; 
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines) 

請注意,我們沒有使用thisnew。它們使JavaScript看起來像Java,除此之外,它們很少有用處。

雖然庫可能修改Object.prototypeArray.prototype,但最終開發人員不應該這樣做。

此外,我們應該(理想)可以這樣做:

  • utils.array.each([1, 2, 3], console.log);
  • utils.array.each([1, 2, 3], document.write);

但是大多數瀏覽器都不會允許它。

希望這有助於。

+0

沒有規則說你必須大寫構造函數的名字。不是每個人都遵循這個慣例,那很好。 – sgroves

+0

不幸的是,你是絕對正確的! JS不強制執行任何命名約定。程序員這樣做是我們的職責。沒有它,我們更可能意外地調用沒有新關鍵字的構造函數。這樣做是災難性的。 (我的答案證明了這一點。) –

+0

好吧,也許。但是有些人和團隊完全不使用大寫公約。沒關係。這是個人選擇。你可以寫出不會大寫構造函數名稱的好代碼 - 最重要的是保持一致。 – sgroves

0

如果我正確理解您的要求,那麼您試圖覆蓋「this」。 我認爲this可以幫到你。

相關問題