爲了更好、更加深入的理解回調函數(callback) --->基於回調函數封裝一個咱們本身的 _each 方法javascript
此方法 將 for each / map / jQuery中的each 三方法中的全部精華優勢融合在一塊兒,進行重寫封裝, 咱們本身的_each 此方法要比原有的強大不少java
//-> _type 本身封裝的強大的 數據類型 方法 在個人文章有專題講解 下面是連接
https://juejin.im/post/5d6dc9b2f265da03b9500f75
var _obj = {
isNumeric: "Number",
isBoolean: 'Boolean',
isString: 'String',
isNull: 'Null',
isUndefined: 'Undefined',
isSymbol: 'Symbol',
isPlainObject: 'Object',
isArray: 'Array',
isRegExp: 'RegExp',
isDate: 'Date',
isFunction: "Function",
isWindow: 'Window'
},
_toString = _obj.toString,
_type = {};
for (var key in _obj) {
if (!_obj.hasOwnProperty(key)) break;
_type[key] = (function () {
var reg = new RegExp("^\\[object " + _obj[key] + "\\]$");
return function anonymous(val) {
return reg.test(_toString.call(val));
}
})();
}
/* 基於ES6 新語法進行封裝 ---> 基於咱們本身封裝的數據類型檢測方法 _type 來實現檢測 <---- * _each:遍歷數組、類數組、對象中的每一項 * @params * obj:須要迭代的數組、類數組、普通對象 * callback:回調函數(每遍歷數組中的某一項,就會把回調函數執行一次; * 並且須要把當前遍歷的內容和索引[屬性值和屬性名]傳給回調函數;* 接收回調函數的返回結果,若是是false,則結束當前的循環; * 若是是其它值,讓返回的值替換數組中的當前項; * 若是沒有返回值,則什麼都不處理...) * 支持第三個參數: * context:傳遞的第三個參數,能夠改變回調函數中的THIS指向,不傳 * 遞默認是window 能夠設置形參默認值 context = window * @return * 返回一個新的數組或者對象(原來的數組或者對象不變) */
//-> 逐行解析
function _each(obj, callback, context = window) {
/* * 首先判斷 obj 是否是數組 或者 (obj裏存在length屬性 而且它的length 屬性是一個數字 ) * 當 符合以上兩個條件時 _type.isArray(obj) --> 這裏說明是一個數組 || (('length' in obj) && _type.isNumeric(obj.length))--> 這裏說明不是一個數組 可是他有length屬性,而且屬性值是數字, 說明他是一個類數組 * * 類數組 和 數組 都符合 isLikeArray 條件 */
let isLikeArray = _type.isArray(obj) || (('length' in obj) && _type.isNumeric(obj.length));
/* * 每循環一次就會把 callback 執行一次 ,因此執行時看callback是否是一個函數 * 檢測 當 callback 不等於一個函數時就它等於一個 匿名空函數 不然什麼都不作 * * 掃盲: Function.prototype() -> 匿名空函數 就是一個匿名空函數,執行時啥效果也沒有 */
typeof callback !== "function" ? callback = Function.prototype : null;
//=>數組或者類數組
/* * 若是 isLikeArray 是數組或者類數組 * for循環遍歷 每循環一次 obj 都會把 callback 執行一次 * callback()不只要執行 還要將裏面的 this 改成第三參數 context ,還要把 數組循環的當前項item 和 索引i 傳給callback() result接收返回值 * 若是 result 接受的返回值爲 false 直接 break 循環結束 * 若是 result 的值爲 "undefined" 結束當前,繼續下輪循環 * 當 返回值的值既不是false 也不是 undefined 也有返回值了 咱們要讓當前的result 返回值替換 數組中的當前項 arr[i] = result; * 最後把克隆後的新數組而且通過替換的 返回 */
if (isLikeArray) {
//-> 將原數組克隆一份
let arr = [...obj];
for (let i = 0; i < arr.length; i++) {
let item = arr[i],
result = callback.call(context, item, i);
if (result === false) break;
if (typeof result === "undefined") continue;
arr[i] = result;
}
return arr;
}
//=>對象的處理
/* * 首先 把對象解構賦值 克隆一份 給 opp 後面都對opp進行操做 防止改變原有隊象的 * 基於 for in 循環 opp 對象 * 若是能進入循環的話 首先判斷是否是本身私有屬性 不是就直接結束循環 break 只循環遍歷本身私有的 * 定義 value 等於 opp[key] 拿到屬性值 result 接收 callback 執行的返回結果 把this 改變 把 value key 傳入 * 若是 result 接受的返回值爲 false 直接 break 循環結束 * 若是 result 的值爲 "undefined" 結束當前,繼續下輪循環 * 當 返回值的值既不是false 也不是 undefined 也有返回值了 咱們要讓當前的result 返回值替換 數組中的當前項 opp[key] = result; * 最後把克隆的 OPP 而且通過替換的 返回 */
let opp = {
...obj
};
for (let key in opp) {
if (!opp.hasOwnProperty(key)) break;
let value = opp[key],
result = callback.call(context, value, key);
if (result === false) break;
if (typeof result === "undefined") continue;
opp[key] = result;
}
return opp;
}
複製代碼
寫了這麼久, 咱們運行一下看看效果
數組
數組
let arr = [10, 20,30,40] ;
let arr2 =_ each(arr, (item,index) => {
console.log(item, index);
if (index >= 2) return false;
return item * 10; //-> 函數執行的返回值會把新數組中的進行替換掉
});
console.log(arr, arr2);
複製代碼
上面的 【100,200,30,40】 30 沒有被替換緣由 --> if (index >= 2) return false; 當大於等2 的時候 後面的代碼不會被執行 因此30 沒有被替換函數
類數組
post
function func() {
let arr = _each(arguments, (item, index) => {
console.log(item, index);
if (index >= 2) return false;
return item * 10;
});
console.log(arguments, arr);
}
func(10, 20, 30, 40);
複製代碼
對象
ui
let obj = {
name: '珠峯',
year: 10,
teacher: '哇咔咔~'
};
let obj2 = _each(obj, function (value, key) {
// console.log(this); //=>document
// console.log(value, key);
if (key === "name") {
return "珠峯培訓@zhufeng";
}
}, document);
console.log(obj, obj2);
//-> 仍是原對象不發生改變
複製代碼