在平常 Coding 中,碼農們確定少不了對數組的操做,其中很經常使用的一個操做就是對數組進行遍歷,查看數組中的元素,而後一頓操做猛如虎。數組
就好像咱們去買水果,在一堆水果中,一個一個看好壞。這個好,嗯,要,放入袋中;這個很差,不要,放回;這個好,嗯,呀 …瀏覽器
在我認識的衆多計算機語言中,如 Java、Python、JS,都有對 forEach 的實現,今天暫且簡單地說說在 JavaScript 中 forEach。函數
學習或研究語言提供的函數 API,通常都會有這麼幾步:學習
代碼很重要,但思惟、認知更重要!this
那麼,很少說,先來看看 forEach 函數的原型:prototype
/** * currentValue : 遍歷到的當前元素 * index : 當前元素的索引值 (可選) * arr : 當前元素所屬的數組對象,即 array (可選) * thisValue : 當執行回調函數時用做 this 的值(參考對象) (可選) * * 返回值: undefined */ 1. array.forEach(function(currentValue, index, arr), thisArg); 2. arr.forEach(callback[, thisArg]);
這裏有兩種函數原型的表達方式,第一種看起來稍微清楚明白點,第二種偏高大上,Linux 上很常見。看我的所接觸的語言及習慣,哪一種適合本身,哪一種能讓本身更容易理解、明白就看哪一種就好,沒必要糾結!code
適合本身的纔是最好的!對象
其中 currentValue 就是遍歷到的當前元素,拿買蘋果做例子,咱們從一堆蘋果中,一個個挑,而 currentValue 就是咱們從水果堆中拿到的那個蘋果;索引
index 是當前元素的索引,也就是咱們手中的蘋果是拿過的蘋果中是第幾個,好比這個是拿的我第二個,那 index 就是 1。爲何是 1 不是 2 呢 ?由於計算機語言是從 0 開始的,這是一個哲學問題;接口
arr 是當前元素所屬的數組對象,說白了就是那一堆蘋果。
而 thisArg,就很難解釋了。仍是看例子吧,說千遍,不如作一步,本身敲一下,運行後,理解可能更深。
後面三個參數都是可選的,無關緊要,估計他們很想哭。
來個栗子:
var array1 = ['a', 'b', 'c']; var array2 = ['1','2','3']; array1.forEach(function(currentValue, index, arr) { console.log(currentValue, index, arr, this); },array2); # 輸出 // 若是給 forEach() 傳遞了 thisArg 參數,當調用時,它將被傳給 callback 函數,做爲它的 this 值。不然,將會傳入 undefined 做爲它的 this 值 > "a" 0 ["a", "b", "c"] ["1", "2", "3"] > "b" 1 ["a", "b", "c"] ["1", "2", "3"] > "c" 2 ["a", "b", "c"] ["1", "2", "3"]
咱們看到,數組的每個元素及他們對應的索引被依次輸入,而 arr 就是它本身,而 this 則是 array2,是咱們在調用 forEach 時傳進去的,在裏面被看成 this 了。
源碼呢 ?
說到這,JavaScript 不像 Java 同樣,它提供的函數的源碼並非用自己本身這種語言編寫的,而是用 C 或 C++ 寫的。這些函數,其實只是一種對外公開的規範,就像是向開發提供的接口同樣。因此嚴格講,JavaScript 不是一門語言,而是一套規範,一套 API。
這與不少語言有着很大的不一樣。
對同一個函數,或者說同一個 API,也有多種不一樣的方式實現,所以,咱們很難像 Java 同樣查看 forEach 的源碼,一個函數,在同一個版本,源碼一致。
咱們只能經過一些公開的參考一些瀏覽器內核公開代碼。
例如,mozilla 的 forEach 源碼:
/* ES5 15.4.4.18. */ function ArrayForEach(callbackfn/*, thisArg*/) { var O = ToObject(this); var len = ToLength(O.length); if (arguments.length === 0) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach"); if (!IsCallable(callbackfn)) ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); var T = arguments.length > 1 ? arguments[1] : void 0; for (var k = 0; k < len; k++) { if (k in O) { callContentFunction(callbackfn, T, O[k], k, O); } } return void 0; }
那咱們能不能根據實際用途效果,參照前面的源碼,本身用 JavaScript 手寫一個 forEach 呢 ?
固然,能夠!
我這裏寫了兩種不一樣的 forEach 的實現,若是你有更好的方式,歡迎貼代碼交流。
1.使用 call 方式
Array.prototype.forEach = function(callback,thisArg){ var len = this.length; for(var i = 0; i < len; i++){ // callback(this[i], i, this); callback.call(thisArg,this[i], i, this); } }
2.使用 bind 方式
Array.prototype.forEach = function(callback,thisArg){ var len = this.length; callback = callback.bind(thisArg); for(var i = 0; i < len; i++){ callback(this[i], i, this); } }
固然,代碼只給了關鍵性代碼,裏面少了不少合理性判斷,特殊處理等。但思路就在那了,更完善的代碼待你們來補充,一塊兒交流。
原創不簡單,碼字不易,點個贊,行不行 !