不唐突的JavaScript:七条核心准则详解

作者:流萤

时间:2026-10-23

浏览:596

本文整理并详解了“不唐突的JavaScript”的七条核心准则。内容涵盖停止盲目假设、利用HTML钩子与节点关系、通过CSS优化DOM遍历、理解浏览器行为、掌握事件处理机制、以及通过命名空间避免全局污染。旨在帮助开发者编写更健壮、可维护且对用户友好的JavaScript代码。

文章目录
1.不要做任何假设

停止假设:JavaScript的不可靠性

(JavaScript是一个不可靠的助手)


实现“不唐突的JavaScript”最关键的一点在于:彻底摒弃任何先入为主的假设。


* 不要默认JavaScript环境可用,应预设其可能不可用,避免直接依赖JS功能。


* 在未通过测试确认浏览器支持特定方法和属性前,不要假设它们可用。


* 不要假设HTML结构符合预期,每次使用时都必须进行检查,若不可用则不执行任何操作。


* 确保JavaScript功能与输入设备无关。


* 需意识到其他脚本可能干扰当前JS功能,因此应尽可能确保脚本作用域的安全与隔离。


在编写脚本前,首要任务是检查目标HTML结构,寻找有助于实现功能的元素。


2.找出钩子和节点关系

利用HTML钩子与节点关系

(HTML是脚本的基石)


编写JS前,先审视目标HTML。若HTML结构混乱或未知,很难设计出优秀的脚本方案——结果往往是创建过多标记,或使应用过度依赖JavaScript。


在HTML中,有两个关键要素需要考虑:钩子(Hooks)和节点关系。


<1>.HTML 钩子


HTML最基础且最重要的钩子是ID,它可通过最快的DOM方法getElementById访问。若文档中所有ID唯一(尽管IE中name与ID存在bug,但优秀类库已解决此问题),使用ID是安全、可靠且易于测试的。


其他钩子包括HTML元素标签和CSS类。HTML元素可通过getElementsByTagName访问,而多数浏览器原生DOM方法尚不支持直接访问CSS类。不过,许多外部类库提供了类似getElementsByClassName的方法。


<2>.HTML 节点关系


HTML另一个有趣之处在于标记间的关系,需思考以下问题:


* 如何以最少DOM遍历最便捷地到达目标节点?


* 修改哪些标记能最大程度访问需修改的子节点?


* 给定元素具备哪些属性或信息可用于定位其他元素?


DOM遍历资源消耗大且速度慢,因此应尽量利用浏览器已内置的技术来实现。


3.把遍历交给专家来做

通过CSS优化DOM遍历

(CSS,更快地遍历DOM)


令人意外的是,许多开发者对使用DOM方法(如getElementsByTagName、nextSibling、previousSibling、parentNode等)遍历DOM感到困惑。有趣的是,我们早已通过另一种技术——CSS——实现了类似功能。


CSS利用选择器遍历DOM以访问目标元素并改变其视觉属性。一段复杂的DOM JavaScript代码,往往可以用一个CSS选择器替代:


代码如下:

var n = document.getElementById('nav');
if(n){
var as = n.getElementsByTagName('a');
if(as.length > 0){
for(var i=0;as[i];i++){
as[i].style.color = '#369';
as[i].style.textDecoration = 'none';
} 
} 
} 
/* 下面的代码与上面功能一样 */
#nav a{
color:#369;
text-decoration:none;
}

这是一个极具价值的技巧。你可以动态为DOM高层元素添加class或更改ID来实现样式控制。若通过JS为body添加CSS类,设计师可轻松定义文档的静态与动态版本。


JavaScript:


代码如下:

var dynamicClass = 'js';
var b = document.body;
b.className = b.className ? b.className + ' js' : 'js';
CSS:
/* 静态版本 */
#nav {
.... 
} 
/* 动态版本 */
body.js #nav {
.... 
} 

4.理解浏览器和用户

理解浏览器行为与用户期望

(在既有的使用模式上创建你所需要的东西)


“不唐突的JavaScript”的核心在于理解浏览器工作原理(尤其是崩溃机制)及用户期望。即使不使用JavaScript,也能创建完全不同的界面。拖拽、折叠区域、滚动条和滑块均可用JS实现,但这不仅是技术问题,还需思考:


* 新界面能否独立于输入设备?若不能,依赖哪些机制?


* 新界面是否遵循浏览器或其他富界面准则(例如,能否直接用鼠标切换多级菜单,还是必须使用Tab键?)


* 哪些功能是依赖JavaScript的,而你又必须提供?


最后一个问题并非难题,因为如需,可使用DOM凭空创建HTML。例如“打印”链接,因浏览器未提供非JS的打印文档功能,需用DOM创建此类链接。同理,可点击的标题栏实现内容展开/收缩也属此类。标题栏无法被键盘激活,但链接可以。因此,需用JS添加链接,使键盘用户也能展开/收缩内容模块。


解决此类问题的极佳资源是设计模式库。至于识别哪些浏览器功能独立于输入设备,需依靠经验积累。首要理解的是事件处理机制。


5.理解事件

掌握事件处理与委托

(事件处理会引起改变)


事件处理是迈向“不唐突的JavaScript”的第二步。重点不在于让所有元素可拖拽、可点击或添加内联处理,而在于理解事件处理是完全可分离的模块。我们已将HTML、CSS和JS分离,但在事件处理的分离上尚未深入。


事件处理器监听文档元素上的变化。若发生事件,处理器会找到一个奇妙的对象(通常名为e参数),该对象告知元素发生了什么及可执行的操作。


大多数事件处理不仅发生在目标元素上,还会在DOM高层级所有元素上发生(focus和blur事件除外)。利用此特性,可为导航列表仅添加一个事件处理器,并通过处理器方法获取真正触发事件的元素。此技术称为事件委托,具有以下优势:


* 只需检查一个元素是否存在,无需检查每个元素


* 可动态添加或删除子节点,无需删除相应的事件处理器


* 可在不同元素上对相同事件做出响应


另一要点是,在事件向父元素传播时可停止它,并可覆盖HTML元素(如链接)的默认行为。但这并非总是好主意,因为浏览器赋予HTML元素这些行为是有原因的。例如,链接可能指向页面内目标,不修改它们可确保用户将当前脚本状态加入书签。


6.为他人着想

命名空间与作用域管理

(命名空间,作用域和模式)


你的代码几乎从来不是文档中唯一的脚本。因此,确保代码中没有其他脚本可覆盖的全局函数或全局变量至关重要。有一些模式可避免此问题,最基本的一点是使用var关键字初始化所有变量。假设编写了以下脚本:


代码如下:

var nav = document.getElementById('nav');
function init(){
// do stuff
} 
function show(){
// do stuff
} 
function reset(){
// do stuff
} 

上述代码包含一个名为nav的全局变量及init、show和reset三个函数。这些函数均可访问nav变量,并通过函数名互相访问:


代码如下:

var nav = document.getElementById('nav');
function init(){
show();
if(nav.className === 'show'){
reset();
} 
// do stuff
} 
function show(){
var c = nav.className;
// do stuff
} 
function reset(){
// do stuff
} 

可将代码封装到对象中以避免上述全局式编码,从而将函数变为对象方法,将全局变量变为对象属性。需使用“名字:值”方式定义方法和属性,并在每个属性或方法后加逗号作为分隔符。


代码如下:

var myScript = {
nav:document.getElementById('nav'),
init:function(){
// do stuff
}, 
show:function(){
// do stuff
}, 
reset:function(){
// do stuff
} 
} 

1

2下一页阅读全文

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章