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 入门基础知识 想学习js的朋友可以参考下
Dec 26 Javascript
javascript 获取url参数和script标签中获取url参数函数代码
Jan 22 Javascript
javascript oop开发滑动(slide)菜单控件
Aug 25 Javascript
JavaScript 32位整型无符号操作示例
Dec 08 Javascript
jQuery实现字符串全部替换的方法【推荐】
Mar 09 Javascript
js遍历json对象所有key及根据动态key获取值的方法(必看)
Mar 09 Javascript
jquery登录的异步验证操作示例
May 09 jQuery
swiper Scrollbar滚动条组件详解
Sep 08 Javascript
浅谈layer的Icon样式以及一些常用的layer窗口使用方法
Sep 11 Javascript
JavaScript中的this/call/apply/bind的使用及区别
Mar 06 Javascript
javascript设计模式 ? 适配器模式原理与应用实例分析
Apr 13 Javascript
如何在selenium中使用js实现定位
Aug 18 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中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
ubuntu下编译安装xcache for php5.3 的具体操作步骤
2013/06/18 PHP
php中smarty模板条件判断用法实例
2015/06/11 PHP
php无法连接mysql数据库的正确解决方法
2016/07/01 PHP
微信支付开发维权通知实例
2016/07/12 PHP
Yii2使用dropdownlist实现地区三级联动功能的方法
2016/07/18 PHP
PHP类的特性实例分析
2016/09/28 PHP
PHP实现动态压缩js与css文件的方法
2018/05/02 PHP
JQuery上传插件Uploadify使用详解及错误处理
2010/04/27 Javascript
Jquery+WebService 校验账号是否已被注册的代码
2010/07/12 Javascript
jQuery EasyUI API 中文文档 - EasyLoader 加载器
2011/09/29 Javascript
js的压缩及jquery压缩探讨(提高页面加载性能/保护劳动成果)
2013/01/29 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
javascript关于open.window子页面执行完成后刷新父页面的问题分析
2015/04/27 Javascript
javascript创建函数的20种方式汇总
2015/06/23 Javascript
BootStrap glyphicons 字体图标实现方法
2016/05/01 Javascript
BootStrap下jQuery自动完成的样式调整
2016/05/30 Javascript
javascript数组常用方法汇总
2016/09/10 Javascript
通过Ajax使用FormData对象无刷新上传文件方法
2016/12/08 Javascript
深入理解Node中的buffer模块
2017/06/03 Javascript
老生常谈JS中的继承及实现代码
2018/07/06 Javascript
vue 父组件给子组件传值子组件给父组件传值的实例代码
2019/04/15 Javascript
Python的ORM框架中SQLAlchemy库的查询操作的教程
2015/04/25 Python
python机器学习理论与实战(四)逻辑回归
2018/01/19 Python
Python自定义装饰器原理与用法实例分析
2018/07/16 Python
PyTorch 对应点相乘、矩阵相乘实例
2019/12/27 Python
pandas使用函数批量处理数据(map、apply、applymap)
2020/11/27 Python
HTML5微信播放全屏问题的解决方法
2017/03/09 HTML / CSS
聊城大学毕业生自荐书
2014/02/01 职场文书
工程专业求职自荐书范文
2014/02/18 职场文书
毕业生实习期转正自我鉴定
2014/09/26 职场文书
离职感谢信
2015/01/21 职场文书
八年级英语教学反思
2016/02/15 职场文书
原生JS实现分页
2022/04/19 Javascript
Windows server 2012 配置Telnet以及用法详解
2022/04/28 Servers
详解CSS3浏览器兼容
2022/12/24 HTML / CSS