留言板记得邮件哦 arthuridea[at]gmail.comRSS订阅

[js开发笔记]是谁动了数组的元素?——从discuz!7.0 BUG修正说开去 - [电脑技术]

今天给一个校友的网站修正bug来的。网站基于Discuz! 7.0版本。

症状是在google chrome下,论坛分栏模式的栏目树形菜单显示异常。其他主流浏览器均正常。

首先迅速定位到bug的位置:

在leftmenu.htm这个模板中,引入的几个javascript,标签书写有问题。文件第62~65行的代码<script>起始标签均多了一个斜杠"/",于是在chrome下不能被正确解析。导致javascript报出未定义异常。

本以为这样就大功告成了,不想还是无法成功显示树形菜单。

于是更进一步,追踪到树形菜单的核心代码。问题发生在createTree这个函数中。chrome浏览器报异常为:未捕获异常:属性pid未定义。tree.js 84行

经过排查,发现javascript中,用for...in...去遍历一个函数内部的数组元素的时候会多一个名称索引为push元素,是一个函数对象。自己随手建一个空的数组用for...in...去遍历输出元素依然会多一个push元素。诶?push不是Array对象的内置方法么?内置对象为什么会在for...in...中被列举出来?追根溯源,查证原来是网站的common.js中重写了Array对象的prototype中的push方法。这样,问题就明朗了。我自然是不敢动common.js里的方法,只有硬着头皮去改tree.js中的实现了。

	var theNode = this.nodes[id];
	var ks=k.toString();
	var kps=id.toString();
	if(!/\d+/.test(ks)||!/\d+/.test(kps)){continue;}

方法虽然有些牵强,总算还是能正常运转。。
不过,痛定思痛,造成这个异常的原因何在?我们知道,IE系列(Trident引擎)、mozilla系列(Gecko引擎)、chrome以及safari(KHTML/WebKit引擎)系列有着不同的渲染引擎,其中又包括HTML的解析部分和对javascript的解析部分。必定是它们对于javascript的实现上有区别所致。而恰恰common.js中又重写了Array的prototype,导致Array实例化出的数组对象发生“变异”。当用for...in...去遍历数组元素时,正常的内置对象比如toString啊pop什么的被隐藏的好好的,变异的push对象就被暴露出来。

总结教训:

1、尽量不要修改原生对象的prototype

2、杜绝变量污染,如果定义变量可能被多次使用请把它放在命名空间内

3、不同的浏览器的js实现不同,单纯遍历数组元素时尽量不要用for...in...(说句题外话,有人做过测试,javascript对于数组的遍历,for...in...的方式效率最低)


收藏到:Del.icio.us





关闭

RSS 什么是RSS?
用IM提醒我内容更新
订阅到QQ邮箱
订阅到鲜果阅读器
订阅到Google阅读器
订阅到抓虾阅读器

关闭

Arthuridea[at]gmail.com

Replace [at] with @