使用!!
操作符转换布尔值http://elevenbeans.github.io/archives/page/2/
有时候我们需要对一个变量查检其是否存在或者检查其值是否有一个有效值,如果存在就返回true
值。可以使用!!
前缀做检测,只要变量的值为:0
、null
、""
、undefined
或者NaN
都将返回的是false
,反之返回的是true
。如下:
var temp = "this is awsome!";
console.log(temp); // this is awsome
console.log(!!temp); // true
var temp = 0;
console.log(temp); // 0
console.log(!!temp); // false
var temp = "";
console.log(temp); // ""
console.log(!!temp); // false
...
当然,!
操作符也可以进行上述转换,不过它恰好会得到相反的布尔值。
使用+
将字符串转换成数字
这个技巧适合用于数字形式的字符串 or 布尔值转数字,否则将返回 NaN
:
var temp = "112";
console.log(temp); // 112
console.log(typeof(temp)); // string
console.log(+temp); // 112
console.log(typeof(+temp)); // number
var temp = "asdf";
console.log(+temp);//NaN
var temp = false;
console.log(+temp);//0
var temp = true;
console.log(+temp);//1
也适用于Date
,它将返回的是时间戳数字:
console.log(new Date()) // Sat May 21 2016 21:24:41 GMT+0800 (CST)
console.log(+new Date()) // 1463837110400
并 &&
条件符
如果你有一段这样的代码:
if (isReady) {
login();
}
可以简写成这样:
isReady && login();
你也可以这样检测一些属性或函数是否存在于一个对象中,如下:
user && user.name
或者 user && user.login();
这个技巧在实际项目中十分常见,它可以有效防止后端接口异常时,返回的数据对象结构变化,或属性 or 方法置空 or 改变导致程序报错终止。
使用||
运算符
在 ES6 中有默认参数这一特性。为了在旧的浏览器中模拟这一特性,可以使用||
操作符,并且将默认值当做第二个参数传入。如果第一个参数返回的值为false
,那么第二个值将会认为是一个默认值。如下:
var fullname; //未初始化 null
var temp = fullname || "Oliver Queen";
console.log(temp); // Oliver Queen
var fullname = "elevenbeans"
var temp = fullname || "Oliver Queen";
console.log(temp); // elevenbeans
优先使用===
,而不是==
==
(或!=
)操作符在需要的时候会自动执行类型转换。===
(或!==
)操作不会执行任何转换。它将比较值和类型,而且在速度上也被认为优于==
。
所以,在类型相同的情况下比较两个值是否相同,优先使用===
。
##能使用 switch/case
语句优先用,否则考虑 if/else
在循环中缓存array.length
在处理一个数组循环时,如果每一次都array.length
去判断大小,代码的性能是非常不好的:
for(var i = 0; i < array.length; i++) {
console.log(array[i]);
}
如果是一个小型数组,这样做还不会有多大影响,如果你要处理的是一个大的数组,这将会导致一些延误。为了避免这种现象出现,可以将array.length做一个缓存:
var length = array.length;
for(var i = 0; i < length; i++) {
console.log(array[i]);
}
检测对象中属性
当你需要检测一些属性是否存在,避免运行未定义的函数或属性时,这个小技巧就显得很有用。例如,你想使用document.querySelector()
来选择一个id,并且让它能兼容 IE6 浏览器,就可以使用如下代码:
if ('querySelector' in document) {
document.querySelector("#id");
} else {
document.getElementById("id");
}
在这个示例中,如果document不存在querySelector
函数,那么就会调用docuemnt.getElementById("id")
。
类似得,前文提到的并条件符 &&
,也可解决这个问题:
if (document && document.querySelector) {
document.querySelector("#id");
} else {
document.getElementById("id");
}
获取数组中最后一个元素
Array.prototype.slice(begin,end)
用来获取 begin 和 end 之间的数组元素。如果你不设置end 参数,将会将数组的默认长度值当作 end 值。如果你设置一个负值作为 begin 的值,那么你可以获取数组的最后 N 个元素。如:
var array = [1,2,3,4,5,6];
console.log(array.slice(-1)); // [6]
console.log(array.slice(-2)); // [5,6]
console.log(array.slice(-3)); // [4,5,6]
数组截断
通过array.length = n
来截断数组,这个小技巧主要用来锁定数组的大小,如果用于删除数组中的一些元素来说,是非常有用的。如下:
var array = [1,2,3,4,5,6];
console.log(array.length); // 6
array.length = 3;
console.log(array.length); // 3
console.log(array); // [1,2,3]
替换所有
String.replace()
函数允许你使用字符串或正则表达式来替换字符串,本身这个函数只替换第一次出现的字符串,你可以使用正则表达多中的 /g
来模拟replaceAll()
函数功能:
var string = "john john";
console.log(string.replace(/hn/, "ana")); // "joana john"
console.log(string.replace(/hn/g, "ana")); // "joana joana"
合并数组
如果你要合并两个数组,一般情况之下你都会使用Array.concat()函数:
var array1 = [1,2,3];
var array2 = [4,5,6];
console.log(array1.concat(array2)); // [1,2,3,4,5,6];
然后这个函数并不适合用来合并两个大型的数组,因为其将消耗大量的内存来存储新创建的数组。在这种情况之个,可以使用Array.push().apply(arr1,arr2)
来替代创建一个新数组。这种方法不是用来创建一个新的数组,其只是将第一个第二个数组合并在一起,同时减少内存的使用:
var array1 = [1,2,3];
var array2 = [4,5,6];
console.log(array1.push.apply(array1, array2)); // [1,2,3,4,5,6];
将 DomNodeList 转换成数组
如果你运行document.querySelectorAll(“p”)
函数时,它可能返回 DOM 元素的数组,也就是NodeList 对象。但这个对象不具有数组的函数功能,比如sort()
、reduce()
、map()
、filter()
等。为了让这些原生的数组函数功能也能用于其上面,需要将节点列表转换成数组。可以使用[].slice.call(elements)
来实现:
var elements = document.querySelectorAll("p"); // NodeList
var arrayElements = [].slice.call(elements); // Now the NodeList is an array
var arrayElements = Array.from(elements); // This is another way of converting NodeList to Array
数组元素的洗牌
对于数组元素的洗牌,不需要使用任何外部的库,比如 Lodash,只要这样做:
var list = [1,2,3,4,5,6];
console.log(list.sort(function() { return Math.random() - 0.5 })); // [2,1,3,5,4,6]
各种随机相关:
从数组中获取一个随机
var items = [12, 548 , ''a'' , 2 , 5478 , ''', 'foo'' , 8852, ''', 'Doe'' , 2145 , 119];
var randomItem = items[Math.floor(Math.random() * items.length)];
在特定范围内获取一个随机数
var x = Math.floor(Math.random() * (max - min + 1)) + min;
在0和设定的最大值之间生成一个数字数组
var numbersArray = [] , max = 100;
for( var i=1; numbersArray.push(i++) < max;); // numbers = [0,1,2,3 ... 100]
生成一个随机的数字字母字符串
function generateRandomAlphaNum(len) {
var rdmstring = "";
for( ; rdmString.length &lt; len; rdmString += Math.random().toString(36).substr(2));
return rdmString.substr(0, len);
}
使用 map() 方法来遍历一个数组里的项
var squares = [1,2,3,4].map(function (val) {
return val * val;
});
// squares will be equal to [1, 4, 9, 16]
基于JSON的序列化和反序列化(serialization and deserialization)
var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString is equal to person object */
自调用的匿名函数
这个经常被称为自调用匿名函数(Self-Invoked Anonymous Function)或者即时调用函数表达式(IIFE-Immediately Invoked Function Expression)。这是一个在创建后立即自动执行的函数,通常如下:
(function(){
// some private code that will be executed automatically
})();
(function(a,b){
var result = a+b;
return result;
})(10,20)
作用:
Javascript 中没用块级作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,产生严重的冲突。
根据 Javascript 函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()
内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。
著名的 JS 库 JQuery 使用的就是这种方法,将JQuery代码包裹在( function (window,undefined){…jquery代码…} (window)
中,在全局作用域中调用 JQuery 代码时,可以达到保护 JQuery 内部变量的作用。
HTML转义函数
这个作用,不言自明啊哈! 直接上代码~
html_encode:function (str){
var s = "";
if (str.length == 0) return "";
s = str.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/ /g, " ")
.replace(/\'/g, "'")
.replace(/\"/g, """)
.replace(/\n/g, "<br>");
return s;
},
html_decode: function (str){
var s = "";
if (str.length == 0) return "";
s = str.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/ /g, " ")
.replace(/'/g, "\'")
.replace(/"/g, "\"")
.replace(/<br>/g, "\n");
return s;
}
Reference:
- 12个JavaScript技巧 by 大漠
1 – 在第一次给一个变量赋值的时候不要忘记使用var
关键字
给一个未定义的变量赋值会导致创建一个全局变量。要避免全局变量。
2 – 使用===,而不是==
==(或!=)操作符在需要的时候会自动执行类型转换。===(或!==)操作不会执行任何转换。它将比较值和类型,而且在速度上也被认为优于==。
1
2
3
4
5
6
7
8
|
[
10
]
===
10
// is false
[
10
]
==
10
// is true
&
#039;10' == 10 // is true
&
#039;10' === 10 // is false
[
]
==
0
// is true
[
]
===
0
// is false
&
#039;' == false // is true but true == "a" is false
&
#039;' === false // is false
|
3 – 使用闭包实现私有变量(译者添加)
1
2
3
4
5
6
7
8
9
10
11
12
|
function
Person
(
name
,
age
)
{
this
.
getName
=
function
(
)
{
return
name
;
}
;
this
.
setName
=
function
(
newName
)
{
name
=
newName
;
}
;
this
.
getAge
=
function
(
)
{
return
age
;
}
;
this
.
setAge
=
function
(
newAge
)
{
age
=
newAge
;
}
;
//未在构造函数中初始化的属性
var
occupation
;
this
.
getOccupation
=
function
(
)
{
return
occupation
;
}
;
this
.
setOccupation
=
function
(
newOcc
)
{
occupation
=
newOcc
;
}
;
}
|
4 – 在语句结尾处使用分号
在语句结尾处使用分号是一个很好的实践。如果你忘记写了你也不会被警告,因为多数情况下JavaScript解释器会帮你加上分号。
5 – 创建对象的构造函数
1
2
3
4
5
6
|
function
Person
(
firstName
,
lastName
)
{
this
.
firstName
=
firstName
;
this
.
lastName
=
lastName
;
}
var
Saad
=
new
Person
(
&
quot
;
Saad
&
quot
;
,
&
quot
;
Mousliki
&
quot
;
)
;
|
6 – 小心使用typeof、instanceof和constructor
1
2
3
4
|
var
arr
=
[
&
quot
;
a
&
quot
;
,
&
quot
;
b
&
quot
;
,
&
quot
;
c
&
quot
;
]
;
typeof
arr
;
// return "object"
arr
instanceof
Array
// true
arr
.
constructor
(
)
;
//[]
|
7 – 创建一个自调用函数(Self-calling Funtion)
这个经常被称为自调用匿名函数(Self-Invoked Anonymous Function)或者即时调用函数表达式(IIFE-Immediately Invoked Function Expression)。这是一个在创建后立即自动执行的函数,通常如下:
1
2
3
4
5
6
7
|
(
function
(
)
{
// some private code that will be executed automatically
}
)
(
)
;
(
function
(
a
,
b
)
{
var
result
=
a
+
b
;
return
result
;
}
)
(
10
,
20
)
|
8- 从数组中获取一个随机项
1
2
3
|
var
items
=
[
12
,
548
,
&
#039;a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];
var
randomItem
=
items
[
Math
.
floor
(
Math
.
random
(
)
*
items
.
length
)
]
;
|
9 – 在特定范围内获取一个随机数
这个代码片段在你想要生成测试数据的时候非常有用,比如一个在最小最大值之间的一个随机薪水值。
1
|
var
x
=
Math
.
floor
(
Math
.
random
(
)
*
(
max
-
min
+
1
)
)
+
min
;
|
10 – 在0和设定的最大值之间生成一个数字数组
1
2
3
|
var
numbersArray
=
[
]
,
max
=
100
;
for
(
var
i
=
1
;
numbersArray
.
push
(
i
++
)
&
lt
;
max
;
)
;
// numbers = [0,1,2,3 ... 100]
|
11 – 生成一个随机的数字字母字符串
1
2
3
4
5
|
function
generateRandomAlphaNum
(
len
)
{
var
rdmstring
=
&
quot
;
&
quot
;
;
for
(
;
rdmString
.
length
&
amp
;
lt
;
len
;
rdmString
+=
Math
.
random
(
)
.
toString
(
36
)
.
substr
(
2
)
)
;
return
rdmString
.
substr
(
0
,
len
)
;
}
|
【译者注:特意查了一下Math.random()生成0到1之间的随机数,number.toString(36)是将这个数字转换成36进制(0-9,a-z),最后substr去掉前面的“0.”字符串】
12 – 打乱一个数字数组
1
2
3
|
var
numbers
=
[
5
,
458
,
120
,
-
215
,
228
,
400
,
122205
,
-
85411
]
;
numbers
=
numbers
.
sort
(
function
(
)
{
return
Math
.
random
(
)
-
0.5
}
)
;
/* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205] */
|
13 – String的trim函数
在Java、C#、PHP和很多其他语言中都有一个经典的 trim 函数,用来去除字符串中的空格符,而在JavaScript中并没有,所以我们需要在String对象上加上这个函数。
1
|
String
.
prototype
.
trim
=
function
(
)
{
return
this
.
replace
(
/
^
\
s
+
|
\
s
+
$
/
g
,
&
quot
;
&
quot
;
)
;
}
;
|
【译者注:去掉字符串的前后空格,不包括字符串内部空格】
14 – 附加(append)一个数组到另一个数组上
1
2
3
4
5
|
var
array1
=
[
12
,
&
quot
;
foo
&
quot
;
,
{
name
:
&
quot
;
Joe
&
quot
;
}
,
-
2458
]
;
var
array2
=
[
&
quot
;
Doe
&
quot
;
,
555
,
100
]
;
Array
.
prototype
.
push
.
apply
(
array1
,
array2
)
;
/* array1 will be equal to [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
|
【译者注:其实concat可以直接实现两个数组的连接,但是它的返回值是一个新的数组。这里是直接改变array1】
15 – 将arguments对象转换成一个数组
1
|
var
argArray
=
Array
.
prototype
.
slice
.
call
(
arguments
)
;
|
【译者注:arguments对象是一个类数组对象,但不是一个真正的数组】
16 – 验证参数是否是数字(number)
1
2
3
|
function
isNumber
(
n
)
{
return
!
isNaN
(
parseFloat
(
n
)
)
&
amp
;
&
amp
;
isFinite
(
n
)
;
}
|
17 – 验证参数是否是数组
1
2
3
|
function
isArray
(
obj
)
{
return
Object
.
prototype
.
toString
.
call
(
obj
)
===
&
#039;[object Array]' ;
}
|
注意:如果toString()方法被重写了(overridden),你使用这个技巧就不能得到想要的结果了。或者你可以使用:
1
|
Array
.
isArray
(
obj
)
;
// 这是一个新的array的方法
|
如果你不在使用多重frames的情况下,你还可以使用 instanceof 方法。但如果你有多个上下文,你就会得到错误的结果。
1
2
3
4
5
6
7
8
9
|
var
myFrame
=
document
.
createElement
(
&
#039;iframe');
document
.
body
.
appendChild
(
myFrame
)
;
var
myArray
=
window
.
frames
[
window
.
frames
.
length
-
1
]
.
Array
;
var
arr
=
new
myArray
(
a
,
b
,
10
)
;
// [a,b,10]
// instanceof will not work correctly, myArray loses his constructor
// constructor is not shared between frames
arr
instanceof
Array
;
// false
|
【译者注:关于如何判断数组网上有不少讨论,大家可以google一下。这篇就写的挺详细的。】
18 – 获取一个数字数组中的最大值或最小值
1
2
3
|
var
numbers
=
[
5
,
458
,
120
,
-
215
,
228
,
400
,
122205
,
-
85411
]
;
var
maxInNumbers
=
Math
.
max
.
apply
(
Math
,
numbers
)
;
var
minInNumbers
=
Math
.
min
.
apply
(
Math
,
numbers
)
;
|
【译者注:这里使用了Function.prototype.apply方法传递参数的技巧】
19 – 清空一个数组
1
2
|
var
myArray
=
[
12
,
222
,
1000
]
;
myArray
.
length
=
0
;
// myArray will be equal to [].
|
20 – 不要使用 delete 来删除一个数组中的项。
使用 splice 而不要使用 delete 来删除数组中的某个项。使用 delete 只是用 undefined 来替换掉原有的项,并不是真正的从数组中删除。
不要使用这种方式:
1
2
3
4
5
|
var
items
=
[
12
,
548
,
&
#039;a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items
.
length
;
// return 11
delete
items
[
3
]
;
// return true
items
.
length
;
// return 11
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
|
而使用:
1
2
3
4
5
|
var
items
=
[
12
,
548
,
&
#039;a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items
.
length
;
// return 11
items
.
splice
(
3
,
1
)
;
items
.
length
;
// return 10
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
|
delete 方法应该被用来删除一个对象的某个属性。
21 – 使用 length 来截短一个数组
跟上面的清空数组的方式类似,我们使用 length 属性来截短一个数组。
1
2
|
var
myArray
=
[
12
,
222
,
1000
,
124
,
98
,
10
]
;
myArray
.
length
=
4
;
// myArray will be equal to [12 , 222 , 1000 , 124].
|
此外,如果你将一个数组的 length 设置成一个比现在大的值,那么这个数组的长度就会被改变,会增加新的 undefined 的项补上。 数组的 length 不是一个只读属性。
1
2
|
myArray
.
length
=
10
;
// the new array length is 10
myArray
[
myArray
.
length
-
1
]
;
// undefined
|
22 – 使用逻辑 AND/OR 做条件判断
1
2
3
|
var
foo
=
10
;
foo
==
10
&
amp
;
&
amp
;
doSomething
(
)
;
// 等价于 if (foo == 10) doSomething();
foo
==
5
||
doSomething
(
)
;
// 等价于 if (foo != 5) doSomething();
|
逻辑 AND 还可以被使用来为函数参数设置默认值
1
2
3
|
function
doSomething
(
arg1
)
{
Arg1
=
arg1
||
10
;
// 如果arg1没有被设置的话,Arg1将被默认设成10
}
|
23 – 使用 map() 方法来遍历一个数组里的项
1
2
3
4
|
var
squares
=
[
1
,
2
,
3
,
4
]
.
map
(
function
(
val
)
{
return
val *
val
;
}
)
;
// squares will be equal to [1, 4, 9, 16]
|
24 – 四舍五入一个数字,保留N位小数
1
2
|
var
num
=
2.443242342
;
num
=
num
.
toFixed
(
4
)
;
// num will be equal to 2.4432
|
25 – 浮点数问题
1
2
3
|
0.1
+
0.2
===
0.3
// is false
9007199254740992
+
1
// is equal to 9007199254740992
9007199254740992
+
2
// is equal to 9007199254740994
|
为什么会这样? 0.1+0.2等于0.30000000000000004。你要知道,所有的JavaScript数字在内部都是以64位二进制表示的浮点数,符合IEEE 754标准。更多的介绍,可以阅读这篇博文。你可以使用 toFixed() 和 toPrecision() 方法解决这个问题。
26 – 使用for-in遍历一个对象内部属性的时候注意检查属性
下面的代码片段能够避免在遍历一个对象属性的时候访问原型的属性
1
2
3
4
5
|
for
(
var
name
in
object
)
{
if
(
object
.
hasOwnProperty
(
name
)
)
{
// do something with name
}
}
|
27 – 逗号操作符
1
2
3
4
|
var
a
=
0
;
var
b
=
(
a
++
,
99
)
;
console
.
log
(
a
)
;
// a will be equal to 1
console
.
log
(
b
)
;
// b is equal to 99
|
28 – 缓存需要计算和查询(calculation or querying)的变量
对于jQuery选择器,我们最好缓存这些DOM元素。
1
2
3
4
|
var
navright
=
document
.
querySelector
(
&
#039;#right');
var
navleft
=
document
.
querySelector
(
&
#039;#left');
var
navup
=
document
.
querySelector
(
&
#039;#up');
var
navdown
=
document
.
querySelector
(
&
#039;#down');
|
29 – 在调用 isFinite()之前验证参数
1
2
3
4
5
6
7
|
isFinite
(
0
/
0
)
;
// false
isFinite
(
&
quot
;
foo
&
quot
;
)
;
// false
isFinite
(
&
quot
;
10
&
quot
;
)
;
// true
isFinite
(
10
)
;
// true
isFinite
(
undifined
)
;
// false
isFinite
(
)
;
// false
isFinite
(
null
)
;
// true !!!
|
30 – 避免数组中的负数索引(negative indexes)
1
2
3
|
var
numbersArray
=
[
1
,
2
,
3
,
4
,
5
]
;
var
from
=
numbersArray
.
indexOf
(
&
quot
;
foo
&
quot
;
)
;
// from is equal to -1
numbersArray
.
splice
(
from
,
2
)
;
// will return [5]
|
确保调用 indexOf 时的参数不是负数。
31 – 基于JSON的序列化和反序列化(serialization and deserialization)
1
2
3
4
5
|
var
person
=
{
name
:
&
#039;Saad', age : 26, department : {ID : 15, name : "R&D"} };
var
stringFromPerson
=
JSON
.
stringify
(
person
)
;
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var
personFromString
=
JSON
.
parse
(
stringFromPerson
)
;
/* personFromString is equal to person object */
|
32 – 避免使用 eval() 和 Function 构造函数
使用 eval 和 Function 构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。
1
2
|
var
func1
=
new
Function
(
functionCode
)
;
var
func2
=
eval
(
functionCode
)
;
|
33 – 避免使用 with()
使用 with() 会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦。
34 – 避免使用 for-in 来遍历一个数组
避免使用这样的方式:
1
2
3
4
|
var
sum
=
0
;
for
(
var
i
in
arrayNumbers
)
{
sum
+=
arrayNumbers
[
i
]
;
}
|
更好的方式是:
1
2
3
4
|
var
sum
=
0
;
for
(
var
i
=
0
,
len
=
arrayNumbers
.
length
;
i
&
lt
;
len
;
i
++
)
{
sum
+=
arrayNumbers
[
i
]
;
}
|
附加的好处是,i 和 len 两个变量的取值都只执行了一次,会比下面的方式更高效:
1
|
for
(
var
i
=
0
;
i
&
lt
;
arrayNumbers
.
length
;
i
++
)
|
为什么?因为arrayNumbers.length每次循环的时候都会被计算。
35 – 在调用 setTimeout() 和 setInterval() 的时候传入函数,而不是字符串。
如果你将字符串传递给 setTimeout() 或者 setInterval(),这个字符串将被如使用 eval 一样被解析,这个是非常耗时的。
不要使用:
1
2
|
setInterval
(
&
#039;doSomethingPeriodically()', 1000);
setTimeOut
(
&
#039;doSomethingAfterFiveSeconds()', 5000)
|
而用:
1
2
|
setInterval
(
doSomethingPeriodically
,
1000
)
;
setTimeOut
(
doSomethingAfterFiveSeconds
,
5000
)
;
|
36 – 使用 switch/case 语句,而不是一长串的 if/else
在判断情况大于2种的时候,使用 switch/case 更高效,而且更优雅(更易于组织代码)。但在判断的情况超过10种的时候不要使用 switch/case。
【译者注:查了一下文献,大家可以看一下这篇介绍】
37 – 在判断数值范围时使用 switch/case
在下面的这种情况,使用 switch/case 判断数值范围的时候是合理的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function
getCategory
(
age
)
{
var
category
=
&
quot
;
&
quot
;
;
switch
(
true
)
{
case
isNaN
(
age
)
:
category
=
&
quot
;
not
an
age
&
quot
;
;
break
;
case
(
age
&
gt
;
=
50
)
:
category
=
&
quot
;
Old
&
quot
;
;
break
;
case
(
age
&
lt
;
=
20
)
:
category
=
&
quot
;
Baby
&
quot
;
;
break
;
default
:
category
=
&
quot
;
Young
&
quot
;
;
break
;
}
;
return
category
;
}
getCategory
(
5
)
;
// will return "Baby"
|
【译者注:一般对于数值范围的判断,用 if/else 会比较合适。 switch/case 更适合对确定数值的判断】
38 – 为创建的对象指定prototype对象
写一个函数来创建一个以指定参数作为prototype的对象是有可能:
1
2
3
4
5
6
|
function
clone
(
object
)
{
function
OneShotConstructor
(
)
{
}
;
OneShotConstructor
.
prototype
=
object
;
return
new
OneShotConstructor
(
)
;
}
clone
(
Array
)
.
prototype
;
// []
|
39 – 一个HTML转义函数
1
2
3
4
5
6
|
function
escapeHTML
(
text
)
{
var
replacements
=
{
&
quot
;
&
lt
;
&
quot
;
:
&
quot
;
&
lt
;
&
quot
;
,
&
quot
;
&
gt
;
&
quot
;
:
&
quot
;
&
gt
;
&
quot
;
,
&
quot
;
&
amp
;
&
quot
;
:
&
quot
;
&
amp
;
&
quot
;
,
&
quot
;
\
&
quot
;
&
quot
;
:
&
quot
;
&
quot
;
&
quot
;
}
;
return
text
.
replace
(
/
[
&
lt
;
&
gt
;
&
amp
;
&
quot
;
]
/
g
,
function
(
character
)
{
return
replacements
[
character
]
;
}
)
;
}
|
40 – 避免在循环内部使用 try-catch-finally
在运行时,每次当 catch 从句被执行的时候,被捕获的异常对象会赋值给一个变量,而在 try-catch-finally 结构中,每次都会新建这个变量。
避免这样的写法:
1
2
3
4
5
6
7
8
9
|
var
object
=
[
&
#039;foo', 'bar'], i;
for
(
i
=
0
,
len
=
object
.
length
;
i
&
lt
;
len
;
i
++
)
{
try
{
// do something that throws an exception
}
catch
(
e
)
{
// handle exception
}
}
|
而使用:
1
2
3
4
5
6
7
8
9
|
var
object
=
[
&
#039;foo', 'bar'], i;
try
{
for
(
i
=
0
,
len
=
object
.
length
;
i
&
lt
;
len
;
i
++
)
{
// do something that throws an exception
}
}
catch
(
e
)
{
// handle exception
}
|
41 – 为 XMLHttpRequests 设置超时。
在一个XHR请求占用很长时间后(比如由于网络问题),你可能需要中止这次请求,那么你可以对XHR调用配套使用 setTimeout()。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
xhr
=
new
XMLHttpRequest
(
)
;
xhr
.
onreadystatechange
=
function
(
)
{
if
(
this
.
readyState
==
4
)
{
clearTimeout
(
timeout
)
;
// do something with response data
}
}
var
timeout
=
setTimeout
(
function
(
)
{
xhr
.
abort
(
)
;
// call error callback
}
,
60
*
1000
/* timeout after a minute */
)
;
xhr
.
open
(
&
#039;GET', url, true);
xhr
.
send
(
)
;
|
此外,一般你应该完全避免同步的Ajax请求。
42 – 处理WebSocket超时
通常,在一个WebSocket连接创建之后,如果你没有活动的话,服务器会在30秒之后断开(time out)你的连接。防火墙也会在一段时间不活动之后断开连接。
为了防止超时的问题,你可能需要间歇性地向服务器端发送空消息。要这样做的话,你可以在你的代码里添加下面的两个函数:一个用来保持连接,另一个用来取消连接的保持。通过这个技巧,你可以控制超时的问题。
使用一个 timerID:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
timerID
=
0
;
function
keepAlive
(
)
{
var
timeout
=
15000
;
if
(
webSocket
.
readyState
==
webSocket
.
OPEN
)
{
webSocket
.
send
(
&
#039;');
}
timerId
=
setTimeout
(
keepAlive
,
timeout
)
;
}
function
cancelKeepAlive
(
)
{
if
(
timerId
)
{
cancelTimeout
(
timerId
)
;
}
}
|
keepAlive()方法应该被添加在webSOcket连接的 onOpen() 方法的最后,而 cancelKeepAlive() 添加在 onClose() 方法的最后。
43 – 牢记,原始运算符始终比函数调用要高效。使用VanillaJS。
举例来说,不使用:
1
2
|
var
min
=
Math
.
min
(
a
,
b
)
;
A
.
push
(
v
)
;
|
而用:
1
2
|
var
min
=
a
&
lt
;
b
?
a
b
;
A
[
A
.
length
]
=
v
;
|
44 – 编码的时候不要忘记使用代码整洁工具。在上线之前使用JSLint和代码压缩工具(minification)(比如JSMin)。《省时利器:代码美化与格式化工具》
45 – JavaScript是不可思议的。最好的JavaScript学习资源。