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学习笔记(十三) js闭包介绍(转)
Jun 20 Javascript
JavaScript词法作用域与调用对象深入理解
Nov 29 Javascript
js将当前时间格式转换成时间搓(自写)
Sep 26 Javascript
表单验证正则表达式实例代码详解
Nov 09 Javascript
JS 滚动事件window.onscroll与position:fixed写兼容IE6的回到顶部组件
Oct 10 Javascript
关于JavaScript中的this指向问题总结篇
Jul 23 Javascript
浅谈vue中使用图片懒加载vue-lazyload插件详细指南
Oct 23 Javascript
Vue源码学习之初始化模块init.js解析
Nov 02 Javascript
微信小程序canvas实现刮刮乐效果
Jul 09 Javascript
微信小程序渲染性能调优小结
Jul 30 Javascript
vue cli3 配置proxy代理无效的解决
Oct 30 Javascript
Ant Design的Table组件去除
Oct 24 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 实现人民币小写转换成大写的方法及大小写转换函数
2017/11/17 PHP
php实现的PDO异常处理操作分析
2018/12/27 PHP
Laravel 验证码认证学习记录小结
2019/12/20 PHP
JavaScript Event学习第四章 传统的事件注册模型
2010/02/07 Javascript
jquerydom对象的事件隐藏显示和对象数组示例
2013/12/10 Javascript
js获取url参数代码实例分享(JS操作URL)
2013/12/13 Javascript
javascript实现的一个随机点名功能
2014/08/26 Javascript
jquery实现两个图片渐变切换效果的方法
2015/06/25 Javascript
javascript点击按钮实现隐藏显示切换效果
2016/02/03 Javascript
Angular2学习笔记——详解路由器模型(Router)
2016/12/02 Javascript
Vuex模块化实现待办事项的状态管理
2017/03/15 Javascript
详解Vuejs2.0之异步跨域请求
2017/04/20 Javascript
浅析Node.js非对称加密方法
2018/01/29 Javascript
JS简单实现动态添加HTML标记的方法示例
2018/04/08 Javascript
js动态引入的四种方法
2018/05/05 Javascript
vue.extend与vue.component的区别和联系
2018/09/19 Javascript
express express-session的使用小结
2018/12/12 Javascript
vue自定义指令用法经典实例小结
2019/03/16 Javascript
vue+element使用动态加载路由方式实现三级菜单页面显示的操作
2020/08/04 Javascript
python复制文件的方法实例详解
2015/05/22 Python
pandas 把数据写入txt文件每行固定写入一定数量的值方法
2018/12/28 Python
Django uwsgi Nginx 的生产环境部署详解
2019/02/02 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
CSS3——齿轮转动关键代码
2013/05/02 HTML / CSS
html5开发三八女王节表白神器
2018/03/07 HTML / CSS
办公室员工岗位工作职责
2014/03/10 职场文书
计算机专业毕业生求职信
2014/04/30 职场文书
2014年创先争优工作总结
2014/12/11 职场文书
学校重阳节活动总结
2015/03/24 职场文书
MySQL 隔离数据列和前缀索引的使用总结
2021/05/14 MySQL
Python中的np.argmin()和np.argmax()函数用法
2021/06/02 Python
Spring Security中用JWT退出登录时遇到的坑
2021/10/16 Java/Android
彻底解决MySQL使用中文乱码的方法
2022/01/22 MySQL
Python识别花卉种类鉴定网络热门植物并自动整理分类
2022/04/08 Python
为自由献出你的心脏!「进击的巨人展 FINAL」2022年6月在台开展
2022/04/13 日漫
python pandas 解析(读取、写入)CSV 文件的操作方法
2022/12/24 Python