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 相关文章推荐
jQuery 页面 Mask实现代码
Jan 09 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
Jul 22 Javascript
基于jquery tab切换(防止页面刷新)
May 23 Javascript
利用javaScript实现点击输入框弹出窗体选择信息
Dec 11 Javascript
jQuery实现的网页换肤效果示例
Sep 20 Javascript
jQuery grep()方法详解及实例代码
Oct 30 Javascript
JavaScript与Java正则表达式写法的区别介绍
Aug 15 Javascript
Gulp实现静态网页模块化的方法详解
Jan 09 Javascript
Vue表单demo v-model双向绑定问题
Jun 29 Javascript
记一次vue去除#问题处理经过小结
Jan 24 Javascript
JavaScript数组去重实现方法小结
Jan 17 Javascript
Webpack的Loader和Plugin的区别
Nov 09 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
PHP中预定义的6种接口介绍
2015/05/12 PHP
通过Email发送PHP错误的方法
2015/07/20 PHP
PHP获取文件扩展名的方法实例总结
2017/06/10 PHP
详解PHP文件的自动加载(autoloading)
2018/02/04 PHP
JavaScript 高级篇之函数 (四)
2012/04/07 Javascript
JavaScript实现自己的DOM选择器原理及代码
2013/03/04 Javascript
JS 获取浏览器和屏幕宽高等信息的实现思路及代码
2013/07/31 Javascript
Javascript加载速度慢的解决方案
2014/03/11 Javascript
JS遍历Json字符串中键值对先转成JSON对象再遍历
2014/08/15 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 图片库
2015/01/09 Javascript
JavaScript判断是否为数字的4种方法及效率比较
2015/04/01 Javascript
javascript实现炫酷的拖动分页
2015/05/11 Javascript
基于JS实现移动端访问PC端页面时跳转到对应的移动端网页
2020/12/24 Javascript
纯JS打造网页中checkbox和radio的美化效果
2016/10/13 Javascript
jQuery获取选中单选按钮radio的值
2016/12/27 Javascript
详解NODEJS基于FFMPEG视频推流测试
2017/11/17 NodeJs
使用setup.py安装python包和卸载python包的方法
2013/11/27 Python
探究Python多进程编程下线程之间变量的共享问题
2015/05/05 Python
Python与Java间Socket通信实例代码
2017/03/06 Python
python生成二维码的实例详解
2017/10/29 Python
python爬虫实例详解
2018/06/19 Python
对Python实现累加函数的方法详解
2019/01/23 Python
如何使用python爬虫爬取要登陆的网站
2019/07/12 Python
python实现一个点绕另一个点旋转后的坐标
2019/12/04 Python
python递归函数求n的阶乘,优缺点及递归次数设置方式
2020/04/02 Python
Python如何使用队列方式实现多线程爬虫
2020/05/12 Python
python和go语言的区别是什么
2020/07/20 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
2020/11/30 Python
CSS3弹性伸缩布局之box布局
2016/07/12 HTML / CSS
英国剑桥包中文官网:The Cambridge Satchel Company中国
2018/11/06 全球购物
我看到了用指针调用函数的不同语法形式
2014/07/16 面试题
大学生专科学习生活的自我评价
2013/12/07 职场文书
网页美工求职信
2014/02/15 职场文书
国庆65周年演讲稿:回首往昔,展望未来
2014/09/21 职场文书
乡镇群众路线教育实践活动整改措施
2014/10/04 职场文书
《检阅》教学反思
2016/02/22 职场文书