JavaScript大杂烩16 - 推荐实践

时间:2021-10-09 14:48:15
JavaScript部分
1. 总是使用===来进行相等判断
原因:由于 == 和 != 操作符存在类型转换问题,而为了保持代码中数据类型的完整性,推荐使用全等 === 和不全等 !=== 操作符。
2. 总是使用";"来结束一条语句
原因:JavaScript允许不使用";"来结束语句,当没发现";"的时候,JavaScript会自己判断何时是语句结束了,这种不确定性大大的提高了出错的几率,所以请严格要求自己,使用";"结束一条语句。
3. 总是使用字面量去创建内置类型的实例
原因:使用new创建的包装类型与使用字面量定义的轻量化的"值类型",拥有的方法列表是一样的,有什么理由用new?
示例:
var name = 'Frank';
var age = 10;
var util = {/*...*/};
var m1 = function() {/*...*/};

4. 总是使用var去定义变量

原因:虽然可以不使用var去定义变量,但是最好不要这么做,除非你想自找麻烦。
示例:
var name = 'Frank',
age
= 10,
util
= {/*...*/};

上面例子中是推荐的一种单行定义多个变量的写法。

5. 如非必要,避免使用全局变量
原因:全局就代表不安全,容易被修改,容易被覆盖,如非必要,避免使用。
6. 在if/for等语句块中,总是写上大括号{},即使只有一条语句
原因:避免歧义。
示例:
if (true) {
alert(
'msg');
}

7. 起始的大括号总是写在上一行行末

原因:避免其他的一些问题导致JavaScript编译器错误断句。
示例:
var foo = function() {
  alert('foo');
};
8. 使用命名空间
原因:避免命名冲突。
示例:
var util = {};
util.checkName
= function() {/*...*/};

9. 除了"构造函数"外,所有的函数(也包括变量)总是使用驼峰命名规范

原因:公认的推荐写法。
示例:
var myName = 'bar';
function checkName(name) {
//...
}

10. 正确使用循环

1). 使用for循环或者foreach方法遍历数组,使用for..in循环遍历对象,这个不多说了,前面遇到多次了。
2). 缓存边界,提高效率,示例如下:
for(var i=0, len = arr.length; i < len; i++) {
//...
}

3). 尽量不要在循环体中创建变量,特别是jQuery对象或者DOM对象,开始循环前缓存起来吧:

var obj = $('.name');
for(/*...*/){
// 使用obj去做某些事
}

11. 尽量多使用单引号表示字符串

原因:HTML元素中多使用双引号,所以JavaScript代码中尽量多使用单引号吧。
示例:
var name = 'Frank';

当然了,出现字符串嵌套的时候就要混用单双引号了。

12. 尽量不使用with语法
with的本意是减少键盘输入。比如
obj.a = obj.b;
obj.c
= obj.d;

可以简写成

with(obj) {
  a
= b;
  c
= d;
}

但是,在实际运行时,解释器会首先判断obj.b和obj.d是否存在,如果不存在的话,再判断全局变量b和d是否存在。这样就导致了低效率,而且可能会导致意外,因此最好不要使用with语句。

13. 尽量不使用eval函数
eval用来直接执行一个字符串。这条语句也是不应该使用的,因为它有性能和安全性的问题,并且使得代码更难阅读。
eval能够做到的事情,不用它也能做到。比如
eval("myValue = myObject." + myKey + ";");

可以直接写成

myValue = myObject[myKey];

至于ajax操作返回的json字符串并执行的需求,可以直接使用JQuery的$.getScript方法实现。

同样的道理适用于setInterval或setTimeout函数的第一个参数,直接传函数吧。
14. 尽量不使用switch贯穿
switch结构中的case语句,默认是顺序执行,除非遇到break,return和throw。有的程序员喜欢利用这个特点,比如
switch(n) {
  
case 1:
  
case 2:
    
break;
}

这样写容易出错,而且难以发现。因此建议避免switch贯穿,凡是有case的地方,一律加上break。

switch(n) {
  
case 1:
    
break;
  
case 2:
    
break;
}

15. 不使用位运算符

原因:Javascript完全套用了Java的位运算符,包括按位与&、按位或|、按位异或^、按位非~、左移<<、带符号的右移>>和用0补足的右移>>>。这套运算符针对的是整数,所以对Javascript完全无用,因为Javascript内部,所有数字都保存为双精度浮点数。如果使用它们的话,Javascript不得不将运算数先转为整数,然后再进行运算,这样就降低了速度。而且"按位与运算符"&同"逻辑与运算符"&&,很容易混淆。
16. 不要扩展内置类型的原型
原因:这样会导致可维护性的问题,因为这会让你的代码的移植性变差。其他的开发人员使用你的代码的时候,可能只需要原生的方法,并不需要额外的功能。
17. 大型程序推荐使用面向对象的写法使用JavaScript(闭包实现封装性,原型链实现继承)
原因:便于扩展,便于使用。
18. 小心使用typeof, instanceof进行类型判断
原因:我们前面在总结对象的若干问题的时候(http://www.cnblogs.com/dxy1982/p/3766606.html)已经详细讲解过这两个操作了,大部分情况下得不到我们想要的结果,其实在弱化类型的动态语言中,个人并不太推荐进行类型检查。这里简单看个例子:
var arr = [0, 1];
alert(
typeof arr); // object
alert(arr instanceof Array); // true
alert(Array.isArray(arr)); // 比instanceof更好的写法

19. 谨慎对浮点数经行判等

这个是所有计算机语言浮点数都可能存在的问题,看例子以及常见方案:
// 错误比较浮点数
alert((0.1+0.2) === 0.3);
// 常见的解决方案
var epsEqual = function () {
var EPSILON = Math.pow(2, -53);
return function epsEqual(x, y) {
return Math.abs(x - y) < EPSILON;
};
}();
alert(epsEqual(
0.1+0.2, 0.3));

20. 时刻检查传入数组中的index参数是否是负数

原因:有的函数可以接收负数,这样用好能达到奇效,但是误用可能导致奇怪的问题。
看例子:
var arr = [1,2,3,4,5];
var index = arr.indexOf('foo'); // index = -1
alert(arr.splice(index, 2)); // 5

是你想要的结果吗?

21. 原始运算符始终比函数高效
原因:原生的操作符执行效率最高。
看例子:
// 使用函数是有开销的
var min = Math.min(a, b);
// 推荐的写法
var min = a < b ? a : b;

22.将脚本放在页面的底部,并且采用HTML5的写法

原因:这个做法的用意是让页面尽可能快的呈献给用户,脚本的加载默认是阻塞的,脚本加载并执行完之前,浏览器不能继续渲染下面的内容。因此,用户将*等待更长时间。这绝对是个有益的实践。看个例子:
<script src="path/to/file.js"></script>
<script src="path/to/anotherFile.js"></script>
</body>
</html>

23. 总是使用数组的toString方法(简单)或者join方法(可以自定义格式)输出数组字符串

原因:啥也别说了,相当快捷:
var arr = [1,2,3,4,5];
alert(arr.toString());
alert(arr.join(
','));
// 稍微复杂一点的例子
var arr = ['item 1', 'item 2', 'item 3', ...];
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';

这种情况下,忘了for循环吧。

24. 时刻提供清晰的调用目标来减少作用域链的检查
原因:提高执行效率。
示例:
// 低效率方法
var url = location.href;
// 相对高效一点的用法
var url = window.location.href;

这个原理同样适用于"多定义局部变量,少定义全局变量"。

 
JQuery部分
1. 总是使用最新版本的JQuery
原因:这个不用多说,大部分情况下,新版本代表更好的性能,更多的功能。
2. 优先使用ID与标记选择器
原因:选择器的选择速度从快到慢依次是:ID,TAG,CLASS。所以如果ID能访问就用id,否则就尝试用tag访问,再不行才用class。快的原因是有原生方法的支持,比如getElementById就很快。当然伪类选择器和属性选择器比上面这些方式更慢。
3. 需要多次使用同一个jQuery对象时缓存该对象
原因:选中某一个网页元素,是开销很大的步骤。所以,使用选择器的次数应该越少越好,并且尽可能缓存选中的结果,便于以后反复使用。
比如,下面这样的写法就是糟糕的写法:
$('#top').find('p.classA');
$(
'#top').find('p.classB');

更好的写法是:

var cached = $('#top');
cached.find(
'p.classA');
cached.find(
'p.classB');

4. 多使用链式操作

$('div').find('h3').eq(2).html('Hello');

原因:采用链式写法时,jQuery自动缓存每一步的结果,因此比非链式写法要快。

5. 使用data方法缓存数据
在jQuery中,可以通过data()方法将数据缓存,虽然使用局部或全局的变量可以保存数据,但变量并不能进行数据的缓存,而且并不依附于某个元素自身;如果使用data方法,可以针对元素定义数据,在元素中存取数据,从而避免数据被循环引用的风险。而且data方法支持存放JSON数据,相当方便:
var cached = $('#p');
cached.data(
'_data');//初始化
cached.data('_data',{//赋值
name: 'haha'
});
cached.data(
'_data').name;//获取JSON中的name值

虽然使用data()方法可以很方便地存取全局性数据,但存储的数据随着操作的变化,会越来越大,如果不及时进行清理,将会影响原有程序的执行。

还有一点,如果你真的要在DOM元素上储存数据,不要写成下面这样:
var elem = $('#elem');
elem.data(key,value);

而要写成

var elem = $('#elem');
$.data(elem[
0],key,value);

根据测试,后一种写法要比前一种写法,快了将近10倍。因为elem.data()方法是定义在jQuery函数的prototype对象上面的,而$.data()方法是定义jQuery函数上面的,调用的时候不从复杂的jQuery对象上调用,所以速度快得多。

6. 如非必要,尽量使用原生方法
原因:原生方法比对应的JQuery方法要快很多,所以如非必要,应少用一些JQuery方法,多使用一些JavaScript的原生DOM方法。比如插入html代码的时候,浏览器原生的innterHTML()方法比jQuery对象的html()更快。又如JavaScript原生循环方法for和while,要比jQuery的.each()方法快,应该优先使用原生方法。
7. 少改动DOM结构
1). 改动DOM结构开销很大,因此不要频繁使用.append()、.insertBefore()和.insetAfter()这样的方法。
如果要插入多个元素,就先把它们合并,然后再一次性插入。根据测试,合并插入比不合并插入,快了将近10倍。
2). 如果你要对一个DOM元素进行大量处理,应该先用.detach()方法,把这个元素从DOM中取出来,处理完毕以后,再重新插回文档。根据测试,使用.detach()方法比不使用时,快了60%。
3). 可以使用DocumentFragment,一个轻量级的文档对象,来作为临时媒介,完成DOM一次性插入。添加元素的时候,我们可以把元素先保存到该对象中,这并不会触发浏览器重绘。当添加结束后,再使用该对象执行一次DOM插入操作,这样就可以避免过多的浏览器重绘。看下面的例子:
function addDivs(element) {
var div;
// Creates a new empty DocumentFragment.
var fragment = document.createDocumentFragment();
for (var i = 0; i < 20; i ++) {
div
= document.createElement('a');
div.innerHTML
= 'Hi!';
fragment.appendChild(div);
}
element.appendChild(fragment);
}

8. 如有可能,多使用工具方法(静态方法),而不是jQuery对象的方法(实例方法)

许多jQuery方法都有两个版本,一个是供jQuery对象使用的版本,另一个是供jQuery函数使用的版本。下面两个例子,都是取出一个元素的文本,使用的都是text()方法。
你既可以使用针对jQuery对象的版本:
var $text = $("#text");
var $ts = $text.text();

也可以使用针对jQuery函数的版本:

var $text = $("#text");
var $ts = $.text($text);

由于后一种针对jQuery函数的版本不通过jQuery对象操作,所以相对开销较小,速度比较快。