编写高质量 JavaScript 代码的一些建议

在 Medium 上看到了两篇关于写高质量 JavaScript 代码的文章,觉得不错,特此搬过来,记下一笔,以待后续查阅。

JavaScript 作为最受欢迎的编程语言之一,被广泛应用在各个领域:网站、服务端、游戏、操作系统等。跟人类一样,编程语言也是随着时间的推移慢慢进化的,而在进化的过 程中,其创建者也会做出一些现在看来很糟糕的决定,给语言加入一些诟病。但是,开发人员也花费了很多时间去总结了很多最佳实践来消除语言自身诟病带来的影 响。如果没有特别的缘由,就应该遵循这些最佳实践,而不是重新造轮子。

1、使用 var 声明变量

使用 var,会在变量定义之处所在的作用域定义一个变量,如果忽略了 var,则该变量会被添加到全局环境 (window 对象)。所有人都知道,全局变量非常邪恶。

2、严格模式

strict

在 JavaScript 文件中以 'use strict'(双引号) 开始,这能阻止使用 JavaScript 的一些不好的实践,想了解更多关于严格模式的信息,戳此:Strict mode-Mozilla Developer Network

3、使用 IIFE–Immediately Invoked Function Expression

IIFE

将代码放进一个立即执行函数中,这会对 JavaScript 文件中定义的变量和函数进行封装而不会被添加到全局环境,也不会污染全局环境。想了解更多,戳此:IIFE

4、使用驼峰表示法

编 程语言是写给人看的,这也是它们为什么是用英语写的原因。因此,代码应该是可读和可理解的。为了使代码可读和可理解,应该一致的方式来编写代码。遵循惯 例,大多数的 JavaScript 应用,工具和库采用驼峰式,遵循这个风格是很重要的,这能避免我们的代码看起来很怪异。遵循一致惯例,也不会对那些想使用你代码的开发者造成困惑。

5、嵌套函数定义并不令人厌恶

nested

在函数作用域需要的地方,可以使用嵌套函数定义,从长远来看,它能保持代码干净和模块化。

6、使用 === 和!==

在 JavaScript 中,== 和 != 操作符是不会检查类型,因而会返回意向不到的结果。想了解更多,戳此:Read More

( 在 你有必要知道的 25 个 JavaScript 面试题 的第一题就有坑 )

7、和使用单引号的人保持一致,而不是双引号

和使用单引号的 JavaScript 开发人员保持一致,跟他们一样,使用单引号。

8、使用 Linter

Linting 是检查源代码以及代码风格的一个过程。 –网络

Get JSHint to your favorite Code Editor

9、代码格式化

<——- 我是分割线——>

上 面一些建议有助于你写出更好的 JavaScript 代码 (Write Better JavaScript),接下来会为如何写出运行更快的 JavaScript 代码提供建议参考 (Write Fast JavaSctipt),每一个建议都带有 jsPerf 的测试。

10、避免类型转换

JavaScript 是动态型的,但如要提高代码运行速度,就不要使用这个特性,而是应该让变量类型保持一致。这同样适用于数组,不要在数组中混合使用不同类型。

1
2
3
4
5
6
{
   var  x =  '2' ;
   var  y = 5;
   x = 2;
   x + y;
}

Test Case

11、String 转 Number

parseInt & parseFloat 是将 (数字) 字符串转换成 Number 类型的最好方式吗?

1
2
3
4
5
6
7
8
9
10
// Different ways of parsing integer/float from strings
parseFloat( "100" )
+ "100"
// integer only
parseInt( "100" , 10)
"100" |0
"100"  >> 0
"100"  << 0
//Only works for positive numbers
"100"  >>> 0

parseInt test ~ parseFloat test

火狐优化了位操作符,其运行速度比 parseInt 和 + 操作符快了 99%,但 Chrome 没有做优化,运行速度还比 parseInt 慢 68%。

parseFloat 则在二者上比 + 操作符都快 (火狐快 28%,Chrome 快 39%)

12、不要重构对象

重构对象是很昂贵的操作,遵循下面的建议来避免:

不使用 delete 操作符

删除一个属性,用 delete 会比通过 null 赋值慢很多,在火狐和 Chrome 中,null 赋值会快 99%,因为它不会修改对象的结构,但是 delete 会。

delete vs null

不要添加属性

定义对象后,不要随后给对象添加属性,而是一开始就应该定义好对象的结构模式,这样运行速度会快很多 (火狐上快 100%,Chrome 上快 89%)

dynamic properties vs pre-defined structure

13、字符串拼接

字符串拼接是相当昂贵的操作,但最好的实现方式是啥呢?肯定不是 Array.prototype.join

字符串拼接运行在不同浏览器上的结果差别很大,我推荐你自己在不同浏览器上运行测试来找到合适的方式。最快的情况下:在火狐上,重关联字符串 (Reassociating strings) 是运行最快的方式;对于 Chrome,在constant fold 的帮助下,使用 Array.prototype.join 是最快的。在二者上的最慢情况似乎是使用String.prototype.concat 和 + 操作符。

字符串连接

14、使用正确的正则方法

在 RegExp.prototype.test 和 String.prototype.search 之间是有性能差异的,看看哪个运行更快:

Regex Methods

看上去 RegExp.prototype.test 比 String.prototype.search 快很多,这是因为二者的运行条件并不是完全一样的,它们是不同的,关于这个的讨论超出了文章范围,你可以看看这个问题:Stack Overflow

在寻找存在的字符串时,RegExp.prototype.test 更快,可能是因为它不返回匹配字符串的索引,而String.prototype.search 仅仅用于返回匹配字符串的索引。

你不应该使用 RegExps 来查找子字符串的索引,而是应该使用 String.prototype.indexOf

String.prototype.search vs String.prototype.indexOf

另一个有趣的基准是 String.prototype.indexOf vs RegExp.prototype.test,我个人期待后者会更快一点,但这出现在火狐中,在 Chrome 中相反。在火狐中,后者快 32%;然后在 Chrome 中,前者快 33%。这种情况,就选择你喜欢的吧。


15、声明 & 传递局部作用域变量

当调用一个函数时,浏览器会进行作用域查找,这个时间花销跟浏览器要查找的作用域数有关。不要依赖全局 / 高层作用域变量,而是创建局部作用域变量,然后传递给函数。查找的作用域数越少,就运行更快。

internal scope vs higher scope vs global

16、不要一切都离不开 jQuery

很多开发者使用 jQuery 来完成很简单的任务,我的意思是,不要因为项目引入了 jQuery,就必须用它,想想,$val() 是一直有必要使用吗?看个示例:

$('input').keyup(function() {    if($(this).val() === 'blah') { ... }
});

学会用平常的 JavaScript 去修改 DOM 的一个最重要的理由是,能写出更高效的代码。

同样的条件,普通的 JavaScript 代码运行更快,看测试:JSPerf Test

$('input').keyup(function() {    if(this.value === 'blah') { ... }
});

17、对于耗时任务,使用 Web Workers

如果你有非常耗时的计算任务,如图像处理,最好使用 Web Workers 让浏览器在后台线程中运行这个任务,并且异步返回处理结果,而不是挂起线程。

文章参考