foreach 原理实现相同功能,foreach 是挂在Array 的原型上面的 所有不能使用在其他情况,如何遍历对象呢?

[1,2,3,4].forEach(function(item,index,arr){
 console.log('当前值:'+item+'当前索引:'+ index + '调用的值:'+arr)
})
 当前值:1当前索引:0调用的值:1,2,3,4
 当前值:2当前索引:1调用的值:1,2,3,4
 当前值:3当前索引:2调用的值:1,2,3,4
 当前值:4当前索引:3调用的值:1,2,3,4



下面提供一个Es6 中的遍历 Object.keys 来实现 转为数组 强制使用 数组的 foreach 方法,这个方法算取巧的一个方法实现吧



var testObj = {
  "name":"西门互联",
  "age":25,
  "job":"Front-end development engineer",
  "blog":"https://textnuxt.lilidong.cn"
}

var testArr = ["西门互联",25,"Front-end development engineer","https://textnuxt.lilidong.cn"]


testArr.forEach(function(item,index,arr){
 console.log('当前值:'+item+'当前索引:'+ index + '调用的值:'+arr)
})


Object.keys(testObj).forEach(function(key){

   console.log(key,testObj[key]);

});



研究foreach原理后,抓住本质,实现一个遍历数组和对象的功能函数来取缔 foreach 不能遍历 对象 功能!!!


遍历的时候要分数组和对象 分别处理 然后通过 .call 改变this 传入 callback 参数 然后就可以回调


注意在调用对象的是否有属性的时候,


hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性



因此这里要使用 原型链上的 hasOwnProperty.call 来改变 this让参数 obj 判断 属性是否存在



var testObj = {
  "name":"西门互联",
  "age":25,
  "job":"Front-end development engineer",
  "blog":"https://textnuxt.lilidong.cn"
}

Object.keys(testObj).forEach((item,index,obj) => {
    console.log('当前值:'+item+'当前索引:'+ index + '调用的值:'+obj)
})



var testObj = {
  "name":"西门互联",
  "age":25,
  "job":"Front-end development engineer",
  "blog":"https://textnuxt.lilidong.cn"
}

var testArr = ["西门互联",25,"Front-end development engineer","https://textnuxt.lilidong.cn"]

var toString = Object.prototype.toString;
function isArray(val) {
 return toString.call(val) === '[object Array]'; //判断数组
}

function forEach(obj, fn) {
 // 排除null 和 undefined 因为null 也是对象
 if (obj === null || typeof obj === 'undefined') {
  return;
 }

 // 强制一个数组,如果还没有可迭代的东西
 if (typeof obj !== 'object') {
  
  obj = [obj];
 }

 if (isArray(obj)) {
  // 循环数组
  for (var i = 0, l = obj.length; i < l; i++) {
   fn.call(null, obj[i], i, obj); //改变this 三个参数 对应 
  }
 } else {
  // 循环对象的key
  for (var key in obj) {
   if (Object.prototype.hasOwnProperty.call(obj, key)) {
    fn.call(null, obj[key], key, obj); //传入 键值 键 调用对象 
   }
  }
 }
}

forEach(testArr,function(item,index,arr){
console.log('当前值:'+item+'--当前索引:'+ index + '--调用的数组:'+arr)
})

forEach(testObj,function(item,key,obj){
 console.log('当前对象键值'+item+'--当前对象key值:'+ key + '--调用的对象:'+JSON.stringify(obj))
})




还有另外一种优雅的实现

// iterator utility
function each (obj, func) {
  if (obj.forEach) {
    obj.forEach(func);
  } else {
    var p;
    for (p in obj) {
      if (obj.hasOwnProperty(p)) {
        func.call(obj, obj[p], p, obj);
      }
    }
  }
}


还有另外一种

export const isArray = Array.isArray;

export function isString(val) {
  return typeof val === 'string';
}
export function isObject(obj) {
  return obj !== null && typeof obj === 'object';
}

export function each(obj, iterator) {

  var i, key;

  if (isArray(obj)) {
    for (i = 0; i < obj.length; i++) {
      iterator.call(obj[i], obj[i], i);
    }
  } else if (isObject(obj)) {
    for (key in obj) {
      if (hasOwnProperty.call(obj, key)) {
        iterator.call(obj[key], obj[key], key);
      }
    }
  }

  return obj;
}