javascript forEach通用循环遍历方法


Posted in Javascript onOctober 11, 2010

上一次的错误太多,排版也出现了问题,重写了一遍,希望大家支持.

循环遍历一个元素是开发中最常见的需求之一,那么让我们来看一个由框架BASE2和Jquery的结合版本吧.

var forEach = (function(){
  //数组与伪数组的遍历
  var _Array_forEach = function (array, block, context) { 
    if (array == null) return; 
    //对String进行特殊处理
    if(typeof array == 'string'){
      array = array.split('');
    }
    var i = 0,length = array.length; 
    for (;i < length && block.call(context, array[i], (i+1), array)!==false; i++) {}  
  }; 
  //对象的遍历
  var _Function_forEach = function (object, block, context) { 
    for (var key in object) { 
      //只遍历本地属性 
      if (object.hasOwnProperty(key)&&block.call(context, object[key], key, object)===false){
        break;
      }
    } 
  }; 
  return function(object, block, context){
    if (object == null) return; 
    if (typeof object.length == "number") { 
     _Array_forEach(object, block, context); 
    }else{  
      _Function_forEach(object, block, context); 
    }
  };
})()

函数本身并不复杂,但很精巧。加了一些简单的注释,想信大家能看懂。

来看一点例子

//1:1  \n 2:2 
forEach([1,2,3,4,5],function(el,index){
  if(index>2){
    return false;
  }
  alert(index+":"+el);
});
 
function print(el,index){
  alert(index+":"+el);
}
//a:a  \n b:b   \n c:c
forEach({a:'a',b:'b',c:'c'},print);
 
//1:笨  \n 2:蛋   \n 3:的   \n 4:座   \n 5:右   \n 6:铭
forEach("笨蛋的座右铭",print);
   
function Person(name, age) { 
 this.name = name || ""; 
 this.age = age || 0; 
}; 
Person.prototype = new Person; 
var fred = new Person("笨蛋的座右铭", 25); 
fred.language = "chinese";//极晚绑定 
//name:jxl \n age:22 \n language:chinese
forEach(fred,print);

注:回调函数中的index参数下标从1开始

为什么不用内置的forEach

和getElementsByClassName一样,内置的forEach效率很高,但是在功能上有局限性,它无法在循环中途退出。而在我们这个forEach中,它可以在处理函数内通过返回false的方式退出循环,更加的灵活。

特别的length属性

length属性是一个很特别的属性,看到数组,大家一定会想到length,那看到带有length属性的对象呢?那大家一定要想到伪数组(类数组)。那什么是伪数组呢?简单的理解就是能通过Array.prototype.slice转换为真正的数组的带有length属性的对象。javascript最为著名的伪数组就是arguments对象。关于伪数组有很多东西,以后我会专门写一篇博文讲这个东西。大家只要记住:不要随便给对象赋予length属性,除非你明确的知道,你准备把它当作伪数组来使用。

我想这个函数是一个简单javascript工具库中的必备函数,它是金字塔的根基,在它的基础上,进行再封装,可以让你的库更强大,更加美丽!

以下是补充

在Base2中找到一个叫forEach的函数,是我见过的最好的实现。挖出来分析一下。它能对各种普通对象,字符串,数组以及类数组进行遍历。如果原游览器的对象已实现此函数,它则调用原对象的函数。

function forEach(object, block, context, fn) {
 if (object == null) return;
 if (!fn) {
  if (typeof object == "function" && object.call) {
   //遍历普通对象
   fn = Function;
  } else if (typeof object.forEach == "function" && object.forEach != arguments.callee) {
   //如果目标已经实现了forEach方法,则使用它自己的forEach方法(如标准游览器的Array对象)
   object.forEach(block, context);
   return;
  } else if (typeof object.length == "number") {
   // 如果是类数组对象或IE的数组对象
   _Array_forEach(object, block, context);
   return;
  }
 }
 _Function_forEach(fn || Object, object, block, context);
};
 
function _Array_forEach(array, block, context) {
 if (array == null) return;
 var i = 0,length = array.length;
 if (typeof array == "string") {
  for (; i < length; i++) {
   block.call(context, array.charAt(i), i, array);
  }
 }else{
  for (;i < length; i++) {
   block.call(context, array[i], i, array);
  }
 }
};
 
 
 _Function_forEach = function(fn, object, block, context) {
  // 这里的fn恒为Function
  for (var key in object) {
    //只遍历本地属性
    if (object.hasOwnProperty(key)) {
    //相当于 block(object[key], key)
    block.call(context, object[key], key, object);
   }
  }
 };

原作者的一些例子(我FQ扒过来了!):

function print(el,index){
 alert(index+" : "+el)
}
forEach ([1, 2, 3], print);
forEach ({a: "aa", b: "bb",c: "cc"}, print);
forEach ("司徒正美", print);
forEach(document.styleSheets,function(el){
 if(el.href) alert(el.href)
});

司徒正美的

function forEach(object, block, context, fn) {
   if (object == null) return;
   if (!fn) {
    if (typeof object == "function" && object.call) {
     //遍历普通对象
     fn = Function;
    } else if (typeof object.forEach == "function" && object.forEach != arguments.callee) {
     //如果目标已经实现了forEach方法,则使用它自己的forEach方法(如标准游览器的Array对象)
     object.forEach(block, context);
     return;
    } else if (typeof object.length == "number") {
     // 如果是类数组对象或IE的数组对象
     _Array_forEach(object, block, context);
     return;
    }
   }
   _Function_forEach(fn || Object, object, block, context);
  };

  function _Array_forEach(array, block, context) {
   if (array == null) return;
   var i = 0,length = array.length;
   if (typeof array == "string")
    array = array.split("");
   for (;i < length; i++) {
    block.call(context, array[i], i, array);
   }
 };


  _Function_forEach = function(fn, object, block, context) {
   // 这里的fn恒为Function
   for (var key in object) {
     //只遍历本地属性
     if (object.hasOwnProperty(key)) {
     //相当于 block(object[key], key)
     block.call(context, object[key], key, object);
    }
   }
  };
 

 function print(el,index){
  alert(index+" : "+el)
 }
 forEach ([1, 2, 3], print);
 forEach ({a: "aa", b: "bb",c: "cc"}, print);
 forEach ("司徒正美", print);
 forEach(document.styleSheets,function(el){
  if(el.href) alert(el.href)
 });

代码

function Person(name, age) {
 this.name = name || "";
 this.age = age || 0;
};
 
 
var fred = new Person("Fred", 38);
fred.language = "English";//极晚绑定
fred.wife = "Wilma";//极晚绑定
forEach(fred,print)

完整代码

function forEach(object, block, context, fn) {
   if (object == null) return;
   if (!fn) {
    if (typeof object == "function" && object.call) {
     //遍历普通对象
     fn = Function;
    } else if (typeof object.forEach == "function" && object.forEach != arguments.callee) {
     //如果目标已经实现了forEach方法,则使用它自己的forEach方法(如标准游览器的Array对象)
     object.forEach(block, context);
     return;
    } else if (typeof object.length == "number") {
     // 如果是类数组对象或IE的数组对象
     _Array_forEach(object, block, context);
     return;
    }
   }
   _Function_forEach(fn || Object, object, block, context);
  };

  function _Array_forEach(array, block, context) {
   if (array == null) return;
   var i = 0,length = array.length;
   if (typeof array == "string")
    array = array.split("");
   for (;i < length; i++) {
    block.call(context, array[i], i, array);
   }
 };

 
  _Function_forEach = function(fn, object, block, context) {
   // 这里的fn恒为Function
   for (var key in object) {
    //只遍历本地属性
     if (object.hasOwnProperty(key)) {
     //相当于 block(object[key], key)
     block.call(context, object[key], key, object);
    }
   }
  };
 
 function print(el,index){
  alert(index+" : "+el)
 }
   function Person(name, age) {
   this.name = name || "";
   this.age = age || 0;
  };
 
  
  var fred = new Person("Fred", 38);
  fred.language = "English";//极晚绑定
  fred.wife = "Wilma";//极晚绑定
  forEach(fred,print)

在Base2中还提供了一个叫unbind的方法,我们可以用它把原生对象的forEach方法剥离出来供我们调用:

核心代码

var _slice = Array.prototype.slice;
function unbind(fn) {
 return function(context) {
  return fn.apply(context, _slice.call(arguments, 1));
 };
};

完整代码

try{
 var _slice = Array.prototype.slice;
  function unbind(fn) {
   return function(context) {
    return fn.apply(context, _slice.call(arguments, 1));
   };
  };
  function print(el,index){
   alert(index+" : "+el)
  }
  var each = unbind(Array.prototype["forEach"])
  var a = {cc : function(e){alert(e)}};
  each(["11111","22222"],a.cc,a)//最后的a可有可无
}catch(e){alert("请在标准浏览器中使用!")}

这篇文章就介绍到这了,希望大家以后多多支持三水点靠木。

Javascript 相关文章推荐
基于JavaScript实现 获取鼠标点击位置坐标的方法
Apr 12 Javascript
JS实现切换标签页效果实例代码
Nov 01 Javascript
Jquery网页内滑动缓冲导航的实现代码
Apr 05 Javascript
JavaScript中window.open用法实例详解
Apr 15 Javascript
基于jquery实现放大镜效果
Aug 17 Javascript
jQuery实现折叠、展开的菜单组效果代码
Sep 16 Javascript
利用Three.js如何实现阴影效果实例代码
Sep 26 Javascript
mui上拉加载更多下拉刷新数据的封装过程
Nov 03 Javascript
Vue通过ref父子组件拿值方法
Sep 12 Javascript
vue下载excel的实现代码后台用post方法
May 10 Javascript
JavaScript中this的全面解析及常见实例
May 14 Javascript
vue计算属性无法监听到数组内部变化的解决方案
Nov 06 Javascript
JavaScript 操作键盘的Enter事件(键盘任何事件),兼容多浏览器
Oct 11 #Javascript
JavaScript isArray()函数判断对象类型的种种方法
Oct 11 #Javascript
JSChart轻量级图形报表工具(内置函数中文参考)
Oct 11 #Javascript
jQuery 表单验证扩展代码(一)
Oct 11 #Javascript
AlertBox 弹出层信息提示框效果实现步骤
Oct 11 #Javascript
基于jQuery的实现简单的分页控件
Oct 10 #Javascript
JQuery的Alert消息框插件使用介绍
Oct 09 #Javascript
You might like
深入探讨<br />和 \r\n两者有什么区别??
2013/06/05 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
2014/07/22 PHP
php中base64_decode与base64_encode加密解密函数实例
2014/11/24 PHP
jQuery Mobile + PHP实现文件上传
2014/12/12 PHP
PHP生成各种随机验证码的方法总结【附demo源码】
2017/06/05 PHP
改善用户体验的五款jQuery插件分享
2011/05/22 Javascript
ie支持function.bind()方法实现代码
2012/12/27 Javascript
node.js中的path.basename方法使用说明
2014/12/09 Javascript
javascript中定义类的方法详解
2015/02/10 Javascript
JavaScript实现数字数组按照倒序排列的方法
2015/04/06 Javascript
Javascript实现苹果悬浮虚拟按钮
2016/04/10 Javascript
全面了解JavaScript的数据类型转换
2016/07/01 Javascript
BootStrap树状图显示功能
2016/11/24 Javascript
jQuery模拟窗口抖动效果
2017/03/15 Javascript
Vue 2.0学习笔记之使用$refs访问Vue中的DOM
2017/12/19 Javascript
在 webpack 中使用 ECharts的实例详解
2018/02/05 Javascript
JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结
2019/06/27 Javascript
浅析vue cli3 封装Svgicon组件正确姿势(推荐)
2020/04/27 Javascript
记录一次websocket封装的过程
2020/11/23 Javascript
[13:38]2015国际邀请赛中国战队出征仪式
2015/05/29 DOTA
浅析python 内置字符串处理函数的使用方法
2014/06/11 Python
Django Form 实时从数据库中获取数据的操作方法
2019/07/25 Python
pytorch实现用CNN和LSTM对文本进行分类方式
2020/01/08 Python
Python 之 Json序列化嵌套类方式
2020/02/27 Python
使用wxpy实现自动发送微信消息功能
2020/02/28 Python
Python HTMLTestRunner可视化报告实现过程解析
2020/04/10 Python
Ubuntu中配置TensorFlow使用环境的方法
2020/04/21 Python
tensorflow实现将ckpt转pb文件的方法
2020/04/22 Python
matlab、python中矩阵的互相导入导出方式
2020/06/01 Python
Python配置pip国内镜像源的实现
2020/08/20 Python
基于django和dropzone.js实现上传文件
2020/11/24 Python
Python3爬虫ChromeDriver的安装实例
2021/02/06 Python
面试感谢信范文
2015/01/22 职场文书
出纳岗位职责
2015/01/31 职场文书
电力企业职工培训心得体会
2016/01/11 职场文书
vue cli4中mockjs在dev环境和build环境的配置详情
2022/04/06 Vue.js