Effective JavaScript(一)

68 Specific Ways to Harness the Power of JavaScript
编写高质量JavaScript代码的68个有效方法

注:本文内容来自同名图书读书笔记,只涉及部分条目,序号会保持原书一致

一.让自己习惯JavaScript

1.了解你使用的JavaScript版本
1
2
3
4
5
6
7
8
9
10
1999. ES3 (ECMAScript)
2009. ES5,ES5加入了严格模式,对于新旧代码的链接,可以选择以下两种方案:
a.不要将进行严格模式检查的文件与不进行严格模式检查的文件连接起来;
b.将其自身包裹在立即调用的函数表达式(Immediately Invoked Function Expression, IIFE)中,来连接多个文件
(function(){
function f(){};
})()
next. ES6
2.理解JavaScript的浮点数
1
2
3
4
5
在js中,数值类型只有一种:number,双精度浮点数
注意浮点数计算的陷阱
0.1+0.2; // 0.30000000000000004
浮点数计算,比较简单的解决办法是先换算成整数计算
3.当心隐式的强制转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在js中, 3+true; // 4
一个未定义的变量会被转换为NaN,标准的库函数isNaN,会将其参数强制转换为数字,
因此对于一个不确定是否为数值类型的变量来说,用其测试不可靠.
isNaN('foo') // true
isNaN(undefined) // true
isNaN({}) // true
isNaN({valueOf:'foo'}) // true
有一个既简单又可靠的检测NaN的习惯用法,由于NaN是js中唯一一个不等于其自身的值,
因此可以通过检测是否等于自身来测试是否为NaN.
var a = NaN;
a !== a; // true
可以将其抽象为工具函数
function isRealNaN(x){
return x !== x;
}
对象通过隐式调用其自身的toString方法转换为字符串
对象也可以通过其自身的valueOf方法转换为数字
js中有7个假值: false/0/-0/""/NaN/null/undefined
4.原始类型优于封装对象
1
2
3
4
5
6
7
8
9
10
11
12
js除了对象类型外,还有5个原始值类型:布尔/数字/字符串/null/undefined.
标准库为布尔/数字/字符串提供了构造函数来封装成对象,例如:
var s = new String('hello');
不同于原始的字符串,String对象是一个真正的对象
typeof 'hello' // 'string'
typeof s // 'object'
var s2 = new String('hello')
s === s2 // false
s == s2 // false
原始类型的封装对象与其原始值,行为可能不一样,原始值类型要优于封装对象
5.避免对混合类型使用 == 运算符
1
2
3
当参数类型不同时, == 运算符应用了隐式强制转换规则
当使用了 === 运算符,可以明确比较两边的值与类型都相等
当比较不同类型的值时,使用自己定义的显示转换可以让程序的行为更明确

二.变量作用域

8.尽量少用全局对象/变量

定义全局变量会污染共享的公共命名空间,可能导致意外的命名冲突,而且不利于模块化,因为它会导致程序中独立组件间的不必要耦合.
由于全局命名空间是js程序中独立组件进行交互的唯一途径,因此,利用全局命名空间的情况是不可避免的.
尽量只在组件或者程序库不得不定义全局变量的时候,使用全局变量.

1
2
3
4
5
6
避免声明全局变量
避免对全局对象添加属性
可以使用全局对象来做平台特性检测,如,要测试当前环境是否支持JSON对象,可以如下实现:
if(!this.JSON){
...

11.熟练使用闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
三个关于闭包的基本事实:
a.js允许你引用在当前函数以外定义的变量 (这个很显然,不解释)
b.即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量,例如:
function doubleAdd(){
var other = 1;
function add(x){
return other + x;
}
return add;
}
var f = doubleAdd();
f(2) // 3
f(4) // 5
以上函数可以修改为匿名函数,如下:
function doubleAdd(){
var other = 1;
return function(x){
return other + x;
}
}
c.闭包可以更新外部变量的值,例如:
function box(){
var val = undefined;
return{
set:function(newVal){val = newVal;}
get:function(newVal){return val;}
};
}
var b = box();
b.set(11);
b.get(); // 11
13.使用立即调用的函数表达式创建局部作用域
1
闭包通过引用而不是值捕获它们的外部变量
16.避免使用eval创建局部变量
1
2
3
4
5
6
7
8
9
10
11
12
调用eval函数会将其参数作为js程序进行解释,但是该程序运行于调用者的局部作用域中,嵌入到程序中的全局变量会被创建为调用程序的局部变量.
保证eval函数不影响外部作用域的一个简单方法是在一个明确的嵌套作用域中运行它,例如:
var y = 'global';
function test(s){
(function(){
eval(s);
})();
return y;
}
test("var y = 'local'"); // global
test("var z = 'local'"); // global
17.间接调用eval函数优于直接调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
通过函数调用方式使用eval,认为是"直接"调用eval函数的方式,例如:
var x = 'global';
function test(){
var x = 'local';
return eval("x");
}
test(); // local
绑定eval到另一个变量名,通过该变量名调用函数会使代码失去对所有局部作用域的访问能力,例如:
var x = 'global';
function test(){
var x = 'local';
var f = eval;
return f("x");
}
test(); // global
尽可能间接调用eval函数,而不要直接调用eval函数.


money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money