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 相关文章推荐
如何在父窗口中得知window.open()出的子窗口关闭事件
Oct 15 Javascript
JS实现切换标签页效果实例代码
Nov 01 Javascript
javascript常见数字进制转换实例分析
Apr 21 Javascript
javascript实现的左右无缝滚动效果
Sep 19 Javascript
js querySelector() 使用方法
Dec 21 Javascript
JavaScript在form表单中使用button按钮实现submit提交方法
Jan 23 Javascript
你真的了解BOM中的history对象吗
Feb 13 Javascript
angularjs2 ng2 密码隐藏显示的实例代码
Aug 01 Javascript
在vscode中统一vue编码风格的方法
Feb 22 Javascript
Vue中在新窗口打开页面及Vue-router的使用
Jun 13 Javascript
Element图表初始大小及窗口自适应实现
Jul 10 Javascript
详解js创建对象的几种方式和对象方法
Mar 01 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
PHP4 与 MySQL 交互使用
2006/10/09 PHP
php倒计时出现-0情况的解决方法
2016/07/28 PHP
php简单构造json多维数组的方法示例
2017/06/08 PHP
ASP.NET jQuery 实例9  通过控件hyperlink实现返回顶部效果
2012/02/03 Javascript
JS中把字符转成ASCII值的函数示例代码
2013/11/21 Javascript
几种设置表单元素中文本输入框不可编辑的方法总结
2013/11/25 Javascript
javascript实现删除前弹出确认框
2015/06/04 Javascript
javascript+HTML5的canvas实现七夕情人节3D玫瑰花效果代码
2015/08/04 Javascript
jquery删除table当前行的实例代码
2016/10/07 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
2016/12/26 Javascript
bootstrap滚动监控器使用方法解析
2017/01/13 Javascript
angular ng-model 无法获取值的处理方法
2018/10/02 Javascript
Vue 实时监听窗口变化 windowresize的两种方法
2018/11/06 Javascript
监听angularJs列表数据是否渲染完毕的方法示例
2018/11/07 Javascript
详解bootstrap-fileinput文件上传控件的亲身实践
2019/03/21 Javascript
vue.js基于v-for实现批量渲染 Json数组对象列表数据示例
2019/08/03 Javascript
浅谈关于vue中scss公用的解决方案
2019/12/02 Javascript
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)
2020/01/14 Javascript
Javascript实现贪吃蛇小游戏(含详细注释)
2020/10/23 Javascript
vue 项目@change多个参数传值多个事件的操作
2021/01/29 Vue.js
用Python展示动态规则法用以解决重叠子问题的示例
2015/04/02 Python
浅谈Python批处理文件夹中的txt文件
2019/03/11 Python
python opencv 二值化 计算白色像素点的实例
2019/07/03 Python
通过 Django Pagination 实现简单分页功能
2019/11/11 Python
Keras中的多分类损失函数用法categorical_crossentropy
2020/06/11 Python
使用python实现下载我们想听的歌曲,速度超快
2020/07/09 Python
Python2.6版本pip安装步骤解析
2020/08/17 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
Sephora丝芙兰印尼官方网站:购买化妆品和护肤品
2018/07/02 全球购物
实习单位接收函
2014/01/11 职场文书
工作经历证明书范文
2014/11/02 职场文书
教师先进个人材料
2014/12/17 职场文书
义诊活动通知
2015/04/24 职场文书
小兵张嘎电影观后感
2015/06/03 职场文书
Golang生成Excel文档的方法步骤
2021/06/09 Golang
Python获取指定日期是"星期几"的6种方法
2022/03/13 Python