《众妙之门——JavaScript与jQuery技术精粹》——2.6 JavaScript代码复查实例

2.6 JavaScript代码复查实例

最近一位开发人员让我对他的代码进行复查并提供改进建议。虽然我并不是代码复查专家(不要被我上面所说的忽悠),我在这里还是给出我提出的问题和解决方案。

问题1
问题:函数和对象没经过任何类型校验就作为参数传递给其他函数。

回复:类型校验是保证输入类型的必要步骤,如果没有进行检查,可能就有输入类型(字符串、日期、数组等)不确定的风险,这些可以轻易地毁掉你未经防御处理的应用程序。对于函数,至少应该进行以下处理:

1.测试以确保传递的变量真实存在;

2.进行typeof检查以阻止执行的输入为非有效函数。

不幸的是,简单的typeof检查是不够的,正如Angus Croll在“Fixing the typeof operator ”中指出,在对包括函数在内的许多内容进行typeof检查时需要注意大量细节。

例如,对空返回对象进行typedef检查在技术上是错误的。实际上,对于除了函数之外的任何对象类型进行typedef检查时,都会返回对象而不区分它们是数组、日期、RegEx还是什么。

可以利用Object.prototype.toString来调用JavaScript内部对象的属性,即[Class],也就是对象的类属性。不幸的是,内置对象通常会覆盖Object.prototype.toString,但是可以对它们加上通用的toString函数:

Object.prototype.toString.call([1,2,3]); //"[object Array]"

你可能也会发现下面Angus的函数是比typeof更适合的选择,对对象、数组以及其他类型调用betterTypeOf()函数来看看会发生什么。

这里,parseInt()函数被盲目地用来解析用户输入的整数值却没有指定基,这样会引起麻烦。

在"JavaScript:the Good Parts "中,Douglas Crockford指出parseInt()函数的调用是非常危险的。尽管你知道输入字符串变量会返回整数,也应该指定一个基作为第二个变量,否则会返回意想不到的输出,考虑下面的例子:

你会对多少开发人员忽略第二个参数感到吃惊,但实际上这经常发生。记住使用者(如果允许自由输入数值)并不一定会根据标准的数值惯例来输入(因为他们太疯狂了!)。我见过020、29319.jpg20、;29337.jpg20以及其他许多输入方式,所以尽可能为各种方式的输入值进行解析,下列使用parseInt()函数的方式偶尔会更好:

问题2
问题:在整个代码库上重复检查是否满足特定于浏览器的条件(例如:特性监测,检查支持的ES5特性等)。

回复:理想情况下,应保持代码库尽可能的“干燥”,有一些好的解决方案可以解决这个问题。例如,可以从加载时间配置模式(也称为加载时间和初始化时间分支)中获益。基本思想是仅测试条件一次(加载应用时)然后在后续检查中来调用这个结果。这种模式在JavaScript库文件中很常见,这些JavaScript库文件在加载时会自我配置,以针对具体浏览器进行优化。

这种模式可以这样实现:

下面的例子演示了如何规范化得到XMLHttpRequest对象。

有一个很著名的例子,Stoyan Stefanov运用这个来添加和删除跨浏览器的事件监听器,在他的《JavaScript Patterns》一书中有介绍。

问题3
问题:定期扩展本机Object.prototype。

回复:扩展本机类型经常会出问题,很少有(如果有的话)著名的代码库敢于扩展Object.prototype类型。事实是并没有一定要扩展它的情况存在。除非是要破坏JavaScript代码中的对象散列表及增加命名冲突可能性,这种扩展的操作一般被认为是糟糕的,这种操作应该是最后选择项(这同扩展自定义对象属性大有不同)。

如果因为某种原因你需要结束扩展对象原型,确保该方法已经不存在并拟出文件使小组中其他成员知道为什么需要这样做,你可以使用以下代码作为指导:

Juriy Zaytsev 有一篇关于“扩展本机和主机对象 ”的非常著名的帖子,可能你会感兴趣。

问题4
问题:有些代码严重阻塞页面,因为它在进行任何进一步操作之前都要等待进程完成或数据加载。

回复:页面阻塞导致用户使用体验差,有很多不损坏应用的解决方法。

一个解决方法是使用“延迟执行”(通过“许诺”和“将来”的概念)。“许诺”的基本思想是与其让某些调用占用资源,不如直接返回一个“将来”会实现的“许诺”。这样将允许编写可异步运行的非阻塞逻辑。常见的做法是在方程中引入一个调用,当请求完成时执行。

我曾经和Julian Aubourg写过一篇全面介绍这种方法的帖子,如果你对通过jQuery实现它感兴趣可以看看这篇帖子。当然也可以利用JavaScript实现。

微框架Q 提供了一个一般性的JS-兼容的“许诺”、“将来”实现方案,它相对而言比较全面,具体如下:

如果你想找一些更基础的可通读程序,这里是Douglas Crockford关于“许诺”的实现方法:

问题5
问题:通常使用“= =”操作符测试某一属性的显式数值等式,但应该使用的是“= = =”操作符。

回复:正如你可能知道也可能不知道的,“= =”操作符在JavaScript中的使用非常自由,即使两个量的值是完全不同的类型也会认为它们相等。这是因为该操作符会优先进行强制类型转换而不是比较,“= = =”却是在两个类型不一样的情况下不会进行强制类型转换,因而会报错。

我之所以在特定类型比较(本例)时更多地推荐使用“= = =”操作符,是因为“= =”操作符有许多陷阱并被许多开发人员认为是不可靠的。

你可能想知道在抽象化的语言(如CoffeeScript)中,由于其不可靠性,“= =”操作符的使用率相对“= = =”完全处于下风。

与其听我片面之言,不如看看下面运用“= =”进行布尔相等性检查的例子,该例子运行会产生无法预期的结果。

上面列表中许多结果等于true,因为JavaScript是一种弱类型化的语言:它尽量多地使用强制类型转换。如果你对上述表达式等于true的原因感兴趣,可以参阅《Annotated ES5指导》,其中的解释更为精彩。

回到复查上面来,如果100%确信进行比较的量不会被用户干扰,可以谨慎地使用“= =”操作符。一定记住,如果有非预期的输入,使用“= = =”操作符会更好。

问题6
问题:非缓存的数组长度被用于所有的for循环中是非常糟糕的,因为你在利用它遍历整个元素集合。

这里有个例子:

回复:这种方法(我依然看到许多开发人员在使用)的问题在于该数组长度在每个循环的迭代中被不必要的重复访问。这会导致程序运行非常慢,尤其是用在HTMLCollection上时(在这种情况下,正如Nicholas C. Zakas在《 High-Performance JavaScript》一书中提到的,对长度进行缓存可以比反复访问它快上190倍)。以下是对数组长度进行缓存的一些方法。

如果你想研究哪种方法表现最佳的话,使用jsPerf 对循环内外的数组捕捉、前缀增量使用、倒计时等进行测试以比较其性能优劣也是可行的。

问题7
问题:jQuery的$.each()函数用于遍历对象和数组,然而在某些情况下则使用for。

回复:在jQuery中,有两种方法可以无缝地遍历对象和数组。通用的$.each 可以遍历这两种类型,$.fn.each() 函数专门用于遍历jQuery对象(其中标准对象利用$()函数封装,你应该更倾向于使用后者)。低级别的$.each()函数执行效果比$.fn.each()函数好,标准的JavaScript for和while循环比这两个都要好,这是经jsPerf测试验证的。以下是一些运行情况也不错的循环:

你可能会发现,Angus Croll的帖子"Rethinking JavaScript for Loops"是对这些建议的一个有趣的延伸。

考虑一个以数据为中心的应用程序,每一个对象或数组都包含大量数据,你应该考虑进行重构来使用以上方法。从拓展性角度说,你应该尽可能地剔除浪费的毫秒数,因为当页面上有数以千计的元素时,时间会累积到很大。

问题8
问题:JSON字符串在内存中以字符串级联的方式建立。

回复:可以通过更优的方式来实现。例如,为什么不使用可以接收JavaScript对象并返回与JSON格式等效的JSON.stringify()函数呢?对象可以按照需要尽可能的复杂或者深度嵌套,这样将会产生更加简单、有效的解决方法。

额外的调试小技巧,如果你想要使得终端控制台显示的JSON更为美观可读,可以使用stringify()函数的以下额外参数实现:

问题9
问题:使用的命名空间模式在技术上是无效的。

回复:应用程序中其他部分使用的命名空间是正确的,而对其存在性的检查是无效的,现有:

问题在于 !MyNamespace会报错:ReferenceError。因为MyNamespace变量之前未经声明。较好的模式是利用内部变量声明布尔类型的强制转换,如下:

当然,可以通过其他许多方法来实现。如果你想阅读更多关于命名空间模式的内容(以及一些命名空间拓展的思路),可以参阅我最近写的"Essential JavaScript Namespacing Patterns"一文,Juriy Zaytsev也写过一篇关于命名空间模式非常全面的文章。

时间: 2024-10-02 19:37:08

《众妙之门——JavaScript与jQuery技术精粹》——2.6 JavaScript代码复查实例的相关文章

《众妙之门——JavaScript与jQuery技术精粹》——导读

前 言 众妙之门--JavaScript与jQuery技术精粹 对于网站开发设计人员而言,在面对选择解决方案时做出正确的决定并不容易.不论是在建立复杂的网站应用还是在改进网站的过程中,都会有很多前期解决方案可供选择,有时选择最合适的一款方案至关重要.本书着重讲述了在选择相应解决方案时务必要注意的事项,即是否稳定并易于定制.是否有实用性并易于理解.是否具有可维护性.兼容性,以及功能的可拓展性. 本书重点阐述了检验代码的重要性以及在执行JavaScript程序时需要避免的问题.所选择的解决方案应能符

《众妙之门——JavaScript与jQuery技术精粹》——第1章 初学JavaScript 需知的七件事 1.1 缩略标记

第1章 初学JavaScript 需知的七件事 我很早以前就开始编写JavaScript代码,很高兴看到这种语言在今天所取得的成功,能成为这个成功故事中的一部分我很开心.关于JavaScript,我写过许多文章.章节以及一整本书,直到今天我仍在寻找新的东西.下文是一些我工作学习过程中激动时刻的记录,大家与其守株待兔,不如自己尝试去体会这种感受. 1.1 缩略标记 众妙之门--JavaScript与jQuery技术精粹 在创建对象和数组过程中可以使用缩略标记是我喜欢JavaScript的重要原因之

《众妙之门——JavaScript与jQuery技术精粹》——2.2 在哪里可以使代码得到复查?

2.2 在哪里可以使代码得到复查? 一般最具挑战性的部分在于找到一个值得信任的有经验的开发者来帮我们复查.以下是一些可以请求别人复查代码的地方(有时是别国语言). . JSMentorsJSMentors是一个讨论JavaScript相关内容的邮件列表,其复查面板中有一大批有经验的开发者(包括JD Dalton.Angus Croll和Nicholas Zakas)在复查人员名单上.这些老师不一定一直在线,但是对于提交的代码他们都会尽全力提供有用的.建设性的反馈意见.如果希望获得的是基于某种特殊

《众妙之门——JavaScript与jQuery技术精粹》——第2章 复查JavaScript 代码的启示2.1 简介

第2章 复查JavaScript 代码的启示 在开始之前,我想问一个问题:你最近一次复查代码是什么时候?代码复查应该是提高整体解决问题能力的最好方式,如果没有利用好它,将会错过发现漏洞和聆听建议的机会,而这些正是使你的代码更加完美所需的. 没有人能写出100%没有漏洞的代码,所以不要为寻求帮助感到羞愧.我们行业中一些非常有经验的开发者,包括架构师和浏览器开发师都会经常要求别人来复查他们的代码,询问别人是否有地方可以改进以避免发生尴尬.代码复查应该被当成一项和其他技术方式解决问题同等重要的方法.

《众妙之门——JavaScript与jQuery技术精粹》——1.8 特定于浏览器的代码就是浪费时间,试试库文件

1.8 特定于浏览器的代码就是浪费时间,试试库文件 在我进行网络开发之初,利用document.all还是document.layers来访问文件还存在很大的争议.我当时选择了document.layers方式,因为我喜欢将层作为当前层文件的思想(我为此还编写了大量document.write方法).这两种方式后来都被淘汰了.Netscape 6问世以后,它仅支持W3C DOM模型,我非常喜欢这种方式,但是终端用户并不在意这些,他们看到的只是这种浏览器没有正确显示大部分互联网内容(实际上是显示了

《众妙之门——JavaScript与jQuery技术精粹》——1.7 与后台交互

1.7 与后台交互 这些年使用JavaScript的经验告诉我:JavaScript包含丰富的交互接口,但在进行数据处理和数据库访问时效果不佳. 最初,我用JavaScript代替Perl的原因是厌倦了每次要将代码复制到目录文件夹中才能运行的情况.后来我学会了利用后台程序来处理数据,而不是将所有的功能用JavaScript来实现,这样使得代码在安全性和语言性上都得到了提高. 访问一个Web服务时,可以得到JSON-P格式的返回值并在客户机上进行大量的数据转换.但是为什么在已经有了服务器并有更多的

《众妙之门——JavaScript与jQuery技术精粹》——1.2 JSON数据格式

1.2 JSON数据格式 在我发现使用JSON存储数据之前,我试过使用各种JavaScript自带的格式来存储内容:带有控制字符进行分隔的数组.字符串等.Douglas Crockford所发明的JSON彻底改变了这一切.运用JSON,你可以使用JavaScript自带的格式存储各种复杂的数据并且不需要进行额外的转换. JSON是JavaScript Object Notation的缩写,使用了我们前面介绍的两种缩略标记. 例如,想要描述一个乐队的话,可以写成: 可以在JavaScript中直接

《众妙之门——JavaScript与jQuery技术精粹》——1.3 JavaScript自带函数(数学、数组以及字符串函数)

1.3 JavaScript自带函数(数学.数组以及字符串函数) 通读了JavaScript的数学.数组和字符串函数后,我意识到它们会让编程变得非常方便,使用它们可避免使用许多循环和条件.例如,当需要找到一组数中的最大数时,需要写这样一个循环: 可以不通过循环而这样实现: 需要注意的是,不能对一个数值数组使用sort()函数,因为它会按照词法排序. 另一个有趣的方法是利用Math.max()函数,返回一列参数中的最大值: Math.max(12,123,3,2,433,4); // return

《众妙之门——JavaScript与jQuery技术精粹》——1.6 允许配置

1.6 允许配置 每当我写完JavaScript源程序并将之公布于众时,人们总是想修改程序,有时是因为人们想进行功能拓展,但大多数时候是因为我的程序太难于定制. 解决方法是在脚本语言中加入配置文件.我在<JavaScript配置对象 >一文中进行了详细的讲述,下面是其中的一些要点. 在整个脚本文件中添加一个对象作为配置文件. 2 .在配置文件中加入使用该脚本程序可能需要改变的所有信息: . CSS的 ID和类名称: . 生成按钮的字符串(比如说标签): . 数据:例如"要展示的图片张