经验总结:5个应该避免的前端糟糕实践
这几天在产品的某个模块上上添加新功能,该模块之前是由其他同事维护。也就是说,需要在同事原有代码的基础上进行修改。过程中遇到了一些坑,主要是由一些不合理的代码实践导致的。
这里抛开大的设计话题,仅挑出其中一些自己认为不是很合理的代码细节。原因很简单:当我们在审视别人代码的时候,总会看到这样那样的不合理之处,而等到自己撸起袖子上阵时,其实也很难保证自己不会犯同样的错误。可能是一时偷懒,也可能是赶需求导致的考虑步骤等。
本文代码示例:点击下载
糟糕实践一:依赖节点之间的顺序我们来看下面代码,大家应该对这样的代码非常熟悉了,这也是初学者比较容易犯的一个错误:节点的查询依赖于节点当前所处的位置。下面
getElementsByTagName(span)[0] 这样的写法存在很大的隐患,很简单,主要节点的顺序一发生变化,就出事了。
h2 不要依赖节点顺序 /h2 div id="1111" span /span , span 爱好:动漫 /span /div script type="text/javascript" var $ = function(id) { return document.getElementById(id); $(1111).getElementsByTagName(span)[0].innerHTML = 昵称:程序猿小卡; /script
比如节点的顺序变成,那就会发生一些意料之外的事情了,第一个span节点之间的“简介:”就被无情地覆盖了。
h2 不要依赖节点顺序 /h2 div id="222" span 简介: /span span /span , span 爱好:动漫 /span /div
千万不要用 element.getElementsByTagName(tagName)[index] 这样的方式可以来获取节点,除非你有非这样做不可的理由。
取而代之可以用类似 element.getElementById(id) 来获取,或者采用下文提到的 element.querySelector(selector) 这样的方式~
糟糕实践二:依赖标签的排版
上面我们已经提到说节点查询的时候不要依赖于节点的顺序,原因是节点的顺序是有可能改变的。那么,如果节点顺序没有“发生变化”,那就能够确保平安无事了吗?答案是未必。
且看下面的代码,也是很常见的代码,获得id为“333”的元素的第一个子节点,并将该子节点的color设置为 #ccc。
h2 顺序没变,但脚本错误了 /h2 div id="333" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div
script type="text/javascript" $(333).childNodes[0].style.color = #ccc; /script
顺序不变也会出事?可能有的同学会有这样的疑惑。好吧,本人稍微有一点排版上的强迫症,看上上面类似的标签排班时,总是忍不住想要去小小调整下,好让标签看上去更清晰些,于是我小小调整了下排版,变成下面这个样子。
h2 顺序没变,但脚本错误了 /h2 div id="444" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div script type="text/javascript" $(444).childNodes[0].style.color = #ccc; /script
子节点顺序并没有发生改变,只是排版变了,按理来说不会有什么影响吧。好,让我们打开chrome看下,控制台下输出这样的信息:
Uncaught TypeError: Cannot set property color of undefined
什么原因呢?眼尖的同学可能已经看出来了,childNodes属性可以获得一个节点的所有子节点,而这些子节点里面包含了文本节点,甚至是标签末尾的换行、空格。不难想到,下面的标签同样会导致同样的bug,而这里的标签跟最初的标签,唯一的区别仅在于:第一个span标签前面多了个空格。
这个bug隐蔽指数相当高,很可能放在那里几年都没有人触发。毕竟,有谁会想到,换个行,加个空格都会导致出bug呢,而且在旧版本IE里面,childNodes是将文本节点排除在外的,也就是说,即使你加了换行、排版,在旧版本IE里测试也是完全ok的,巨坑。
h2 顺序没变,但脚本错误了 /h2 div id="555" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div script type="text/javascript" $(555).childNodes[0].style.color = #ccc; /script
参见糟糕实践一的解决方案
糟糕实践三:依赖特定的节点类型
项目中依赖的基础库是jQuery,jq提供了非常强大的选择器,很常见的就是可以通过节点类型进行选择,比如下面代码。如果你那么写的话,接手你代码的兄弟估计会恨死你。
h2 依赖节点类型 /h2 div id="666" ul /ul /div script type="text/javascript" src="jquery.js" /script script type="text/javascript" $(#666 ul).html( li 昵称:程序猿小卡 /li li 爱好:漫画 /li ); /script
问题很明显,$(#666 ul)选中了id为666的节点下所有节点类型为UL的子节点、孙节点、曾孙节点。。。我就掉这个坑里了,但是需要在上面加多个下拉列表,于是毫不犹豫地采用UL来模拟,大致如下。运行的结果绝对让你抓狂。
h2 依赖节点类型 /h2 div id="777" ul /ul li 选项一 /li li 选项二 /li li 选项三 /li /ul /div script type="text/javascript" src="jquery.js" /script script type="text/javascript" $(#777 ul).html( li 昵称:程序猿小卡 /li li 爱好:漫画 /li ); /script解决方案
参见糟糕实践一的解决方案。
糟糕实践四:不合理利用元素选择器声明样式
跟上面的例子其实很类似,还是用上面的标签来说明问题。同事的愿望很朴素,就是希望将ul节点下的文本都设置为红色而已。
style type="text/css" color: red; /style h2 依赖节点类型 /h2 div id="666" ul /ul /div
然后,我往里面查了另一个ul元素来模拟下拉列表,悲剧了,原先声明的样式伤及无辜。。
h2 依赖节点类型 /h2 div id="777" ul /ul li 选项一 /li li 选项二 /li li 选项三 /li /ul /div解决方案
尽可能地避免通过元素选择器来声明样式(reset css的除外),如果非用不可,那么尽可能地将杀伤范围限制得足够小,如在某个特定的id、class内部用元素选择器,就像下面这样这样。
注意:尽管这样做看上去安全了些,但还是有不小的隐患,千万小心
.restrict_style ul{ color: red; } // 通过外层容器,限制选择器的
糟糕实践五:节点查询依赖于样式类名
在一个页面中,id是唯一的,给太多的节点加上id,很容易造成节点id的冲突。常用的推荐解决方案是,给最外层的容器节点加上id,而对于子节点,则加上相应的class,以此达到方便查询、避免冲突的目的。下面这样的代码相信大家不陌生,包括不少开源组件都是这么个思路。
h2 节点查询依赖于类名 /h2 div id="888" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div script type="text/javascript" src="jquery.js" /script script type="text/javascript" $(#888 .nick).css(color, green); $(#888 .hobby).css(color, orange); /script
上面的代码看上去没什么问题,那究竟为什么说它糟糕呢?因为:1、不利于样式重构 2、修改容易导致bug
假设某个晴朗的早晨,产品同学找到你说,这里这里的样式需要改版,你稍微一评估,自信满满地说:没问题,很简单。于是你就开工了,既然是改版,肯定是大动刀了。过了一会,你的眼球突然被 span /span 这个标签吸引了:好好的炎黄子孙class名干嘛起得这样洋里洋气的,太装了吧(很不恰当的例子哈,只是为了说明因某些原因需要修改类名)。于是果断将“nick”改成了“nicheng”,多通俗易懂啊。
于是,悲剧了,在本文的例子里,把“nick”改成“nicheng”,只是会导致样式稍微有点不正常,但严重的时候脚本错误都有可能
h2 节点查询依赖于类名 /h2 div id="999" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div script type="text/javascript" src="jquery.js" /script script type="text/javascript" $(#999 .nick).css(color, green); // 节点取不到了 $(#999 .hobby).css(color, orange); $(#999 .nick)[0].innerHTML = 程序猿小卡; /// 出错了,因为$(#999 .nick)[0]为undefined /script
大家都推崇的开发方式(外层id,内层class),是不是就不要用了呢?当然不是,只不过可以稍微调整下:
1、外层容器用id
2、子节点用class,但class前需要加上“js-”等特殊前缀,标识该样式为js代码里需要用到的。对这样的class不要随便动它,如果需要修改,请先搜索下整个工程目录,确保你的修改不会导致bug。
简单修改下上面的例子,好了,nick、hobby,随你修改了~
h2 节点查询不依赖于样式类名 /h2 div id="1010" span 昵称:程序猿小卡 /span span 爱好:动漫 /span /div script type="text/javascript" src="jquery.js" /script script type="text/javascript" $(#999 .js-nick).css(color, green); // 节点取不到了 $(#999 .js-hobby).css(color, orange); $(#999 .js-nick)[0].innerHTML = 程序猿小卡; /// 出错了,因为$(#999 .nick)[0]为undefined /script
更多糟糕实践
待补充
相关文章
- 数据透视表上线!如何在纯前端实现这个强大的数据分析功能?
- 08·灵魂前端工程师养成-HTML实践&手机调试
- 19·灵魂前端工程师养成-JavaScript数据类型和运算符
- web前端网页设计制作_网页制作教程
- 前端工程化在WMS 6.0中的实践
- 前端页面图片加载失败显示默认图片
- 报名 | 技术沙龙前端专场:美团在跨端和低代码方向的探索与实践
- jQuery Validate 前端表单验证
- java websocket client_前端和后端哪个累
- 10分钟学会前端工程化(webpack5.0)
- 美团前端手写面试题总结
- 前端leetcde算法面试套路之回溯
- 从 polyrepo 到 monorepo,前端代码仓库改造工程实践
- 树莓派海文SeaFile配置Nginx前端反代并启用HTTPS全攻略
- 前端leetcde算法面试套路之堆5失败
- 第44篇:绕过前端加密的账号密码爆破-易语言网页填表模块
- 前端常考vue面试题(必备)_2023-03-15
- 体验Linux开发前端的快感(linux开发前端)
- 前端开发技术中,Redis成为不可或缺的重要组件(前端 redis)