Javascript技巧之不要用for in语句对数组进行遍历


Posted in Javascript onOctober 20, 2010

一,为什么不要用for in语句

jqModal这个jquery插件估计很多人都使用过,在jqModal源码内部,有一个函数为hs,其中有个嵌套循环如下,

for(var i in {jqmShow:1,jqmHide:1}) 
for(var s in this[i]) 
if(H[this[i][s]]) 
H[this[i][s]].w[i](this); 
return F; 
}

第一个for in遍历的目标是个匿名对象,没有问题。
第二个for in遍历,根据上下文确认this[i]是一个数组对象(Array)。
很多JS先驱者都告诫过我们不要对数组对象使用for in语句进行遍历,原因除了性能外,还有可能产生意料之内的bug。不听先人言,吃亏在眼前呵呵。
今天偶拿jqModal为例,说明下这种bug到底什么时候会出现,当引以为戒。
二,问题重现
关键词:原生Array类、扩展Array类
for in 语句对数组对象进行遍历潜在的bug在于:如果原生Array类被其他的js脚本库进行了原型扩展(比如多加一个toJSON方法即Array.prototype.toJSON=xxxx),那么用for in遍历扩展后的Array对象的逻辑将与遍历原生Array对象的逻辑发生差异。
举个简单的例子,
var x=[1]; 
for(var s in x){ 
alert(s); 
};

按常理,如果Array是原生js类,上面语句应该只执行一次alert方法,且s为数组的索引0。但是,如果Array类被扩展了,多了一个toJSON方法,那么上面的语句将执行两次alert,第一次s为索引0,第二次s为方法名'toJSON'。

如果你设计的代码的逻辑以原生Array类为基准,在某一天你的同事在页面里面引用了一个第三方的JS库,这个库又恰好扩展了Array类,结果将难以想象,很有可能原来的代码逻辑将不再成立。

关于这种扩展原生JS类的库,很有名的一个就是prototype.js,它给Array类扩展了很多方法诸如toJSON,each等等。我现在明白为啥jquery的创始人曾经对prototype火大了(不少人因为特殊原因在一个页面里用jquery同时又用prototype,会有很多意料之外的冲突问题,仅仅一个noConflict是无法解决的)。另外,jqModal的作者如果看得懂我这篇文章估计也会对埋怨prototype,说:“我用for in对数组遍历是不明智的,但是更该死的还是prototype。。。”

如上所述,如果你在用jqModal,同时因为别的原因在用prototype,恭喜你中招了。冲突将导致jqModal的弹框在ie6、ie7下面将无法利用closeClass设置的按钮进行自动关闭。跟踪调试代码你将发现,异常的地方就在本文开头提到的hs方法的for in 循环中。。。
三,解决问题
遍历数组的地方,用for var 语句代替for in。

Javascript 相关文章推荐
javascript 解决表单仍然提交即使监听处理函数返回false
Mar 14 Javascript
js 数值转换为3位逗号分隔的示例代码
Feb 19 Javascript
JavaScript DOM元素尺寸和位置
Apr 13 Javascript
实例代码详解jquery.slides.js
Nov 16 Javascript
Vuejs第十一篇组件之slot内容分发实例详解
Sep 09 Javascript
AngularJS中$watch和$timeout的使用示例
Sep 20 Javascript
jQuery EasyUi 验证功能实例解析
Jan 06 Javascript
React复制到剪贴板的示例代码
Aug 22 Javascript
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
Oct 26 Javascript
简单理解Vue中的nextTick方法
Jan 30 Javascript
javascript function(函数类型)使用与注意事项小结
Jun 10 Javascript
Vue 自定义指令实现一键 Copy功能
Sep 16 Javascript
来自国外的14个图片放大编辑的jQuery插件整理
Oct 20 #Javascript
理解Javascript_12_执行模型浅析
Oct 18 #Javascript
理解Javascript_11_constructor实现原理
Oct 18 #Javascript
关于js中window.location.href,location.href,parent.location.href,top.location.href的用法与区别
Oct 18 #Javascript
jQuery Validation实例代码 让验证变得如此容易
Oct 18 #Javascript
jQuery 验证插件 Web前端设计模式(asp.net)
Oct 17 #Javascript
基本jquery的控制tabs打开的数量的代码
Oct 17 #Javascript
You might like
删除数组元素实用的PHP数组函数
2008/08/18 PHP
PHPMYADMIN 简明安装教程 推荐
2010/03/07 PHP
php判断GIF图片是否为动画的方法
2020/09/04 PHP
ThinkPHP独立分组使用的注意事项
2014/11/25 PHP
服务器上配置PHP运行环境教程
2015/02/12 PHP
完美解决php 导出excle的.csv格式的数据时乱码问题
2017/02/18 PHP
PHP长网址与短网址的实现方法
2017/10/13 PHP
php设计模式之装饰模式应用案例详解
2019/06/17 PHP
laravel 出现command not found问题的解决方案
2019/10/23 PHP
js获取系统的根路径实现介绍
2013/09/08 Javascript
javascript 按键事件(兼容各浏览器)
2013/12/20 Javascript
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
jquery实现隐藏在左侧的弹性弹出菜单效果
2015/09/18 Javascript
jquery实现简单的全选和反选功能
2016/01/02 Javascript
BootStrap的弹出框(Popover)支持鼠标移到弹出层上弹窗层不隐藏的原因及解决办法
2016/04/03 Javascript
JavaScript易错知识点整理
2016/12/05 Javascript
vue双向数据绑定原理探究(附demo)
2017/01/17 Javascript
vue-resource 拦截器使用详解
2017/02/21 Javascript
vue如何实现observer和watcher源码解析
2017/03/09 Javascript
AngularJS 单选框及多选框的双向动态绑定
2017/04/20 Javascript
H5基于iScroll实现下拉刷新和上拉加载更多
2017/07/18 Javascript
jQuery实现base64前台加密解密功能详解
2017/08/29 jQuery
探索Vue高阶组件的使用
2018/01/08 Javascript
Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现
2019/04/01 Javascript
vue 页面跳转的实现方式
2021/01/12 Vue.js
在Python的Django框架中编写错误提示页面
2015/07/22 Python
VPS CENTOS 上配置python,mysql,nginx,uwsgi,django的方法详解
2019/07/01 Python
Django中create和save方法的不同
2019/08/13 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
英国排名第一的最新设计师品牌手表独立零售商:TIC Watches
2016/09/24 全球购物
大专毕业生自我鉴定
2013/11/21 职场文书
项目计划书范文
2014/01/09 职场文书
公司行政专员岗位职责
2014/08/24 职场文书
咖啡厅商业计划书
2014/09/15 职场文书
Mysql中一千万条数据怎么快速查询
2021/12/06 MySQL