null 和 undefined
Undefined相當於一個變量並沒有明確的被賦值(是否被賦值, 可能無心忽略, 邏輯問題) JS的怪異之處就在於undefined真的是一個可以使用的值。
> var foo; > foo undefined
同理,當缺失參數時 JavaScript 會分配一個 undefined:
> function id(x) { return x }
> id()
undefined
a = 1;
a !== undefined // true
a = undefined
var b
a === b //true
Null相當於變量被明確指定了沒有值,而不是由於意外的原因被忽略掉了(賦值null, 正當邏輯)
參與運算
JS的null如果進入運算,真的會被解析成為0或false:
(1 + null) # 1 (1 * null) # 0 (1 * null) # Infinity
undefined進入運算,一律得到NaN:
(1 + undefined) # NaN (1 * undefined) # NaN (1 / undefined) # NaN
邏輯判斷
null和undefined邏輯判斷時都認為是false。
只用一個判斷,就可以同時檢驗這兩項是否為真:
//也會把 false, -0, +0, NaN 與 '' 當成“空值”
if (v) {
// v 有值
} else {
// v 沒有值
}
但是如果碰到大坑==的時候
var foo; console.log(foo == null); // true console.log(foo == undefined); // true console.log(foo === null); // false console.log(foo === undefined); // true console.log(null == undefined); // true
好的做法, 一律使用===
判斷一個量已定義且非空,只使用:if (a !== null && a !== undefined)。
=== 和 ==
1.==用來判斷兩個值是否相等
當兩個值類型不同時,會發生自動轉換,得到的結果非常不符合直覺,這可能不是你想要的結果。
"" == "0" // false 0 == "" // true 0 == "0" // true false == "false" // false false == "0" // true false == undefined // false false == null // false null == undefined // true " \t\r\n" == 0 // true
2.===
類型+值比較
"如果兩邊的操作數具有相同的類型和值,===返回true,!==返回false。"——《JavaScript:語言精粹》
最佳實踐:
任何時候在比較操作中使用 === 和 !==
json操作
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 */
to string
var obj = {
name: 'myObj'
};
JSON.stringify(obj);
函數對象及匿名函數
函數對象賦值
var slice_func = [].slice
//slice_func()
var a = function() {
};
// a()
var a = {
fun : function() {
};
}
// a.fun()
someElement.addEventListener("click", function(e) {
// I'm anonymous!
});
以及
var f = function foo(){
return typeof foo; // foo是在內部作用域內有效
};
// foo在外部用於是不可見的
typeof foo; // "undefined"
f(); // "function"
匿名函數
from
var name = 'Chris';
var age = '34';
var status = 'single';
function createMember(){
// [...]
}
function getMemberDetails(){
// [...]
}
to
var myApplication = function(){
var name = 'Chris';
var age = '34';
var status = 'single';
return{
createMember:function(){
// [...]
},
getMemberDetails:function(){
// [...]
}
}
}();
// myApplication.createMember() and
// myApplication.getMemberDetails() now works.
最佳實踐
1.定義多個變量時,省略var關鍵字,用逗號代替
var someItem = 'some string'; var anotherItem = 'another string'; var oneMoreItem = 'one more string';
更好的做法
var someItem = 'some string', anotherItem = 'another string', oneMoreItem = 'one more string';
2.謹記,不要省略分號, 不要省略花括號
省略分號,可能導致更大的,未知的,難以發現的問題
var someItem = 'some string'
function doSomething() {
return 'something'
}
更好的做法
var someItem = 'some string';
function doSomething() {
return 'something';
}
3.使用{}代替 new Ojbect()
在JavaScript中創建對象的方法有多種。可能是傳統的方法是使用”new”加構造函數,像下面這樣:
var o = new Object();
o.name = 'Jeffrey';
o.lastName = 'Way';
o.someFunction = function() {
console.log(this.name);
}
更好的做法
var o = {}; //空對象
var o = {
name: 'Jeffrey',
lastName = 'Way',
someFunction : function() {
console.log(this.name);
}
};
只要把多個全局變量都整理在一個名稱空間下,擬將顯著降低與其他應用程序、組件或類庫之間產生糟糕的相互影響的可能性。——Douglas Crockford
4.使用[]代替 new Array()
var a = new Array(); a[0] = "Joe"; a[1] = 'Plumber';
更好的做法:
var a = ['Joe','Plumber'];
5.typeof判斷
typeof一般只能返回如下幾個結果:number,boolean,string,function,object,undefined
expr:
typeof xx === '' typeof xx !== ''
e.g.
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 盡管NaN是"Not-A-Number"的縮寫,意思是"不是一個數字"
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的肯定是一個字符串
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一個未定義的變量,或者一個定義了卻未賦初值的變量
// Objects
typeof {a:1} === 'object';
typeof [1, 2, 4] === 'object'; // 使用Array.isArray或者Object.prototype.toString.call方法可以分辨出一個數組和真實的對象
typeof new Date() === 'object';
// Functions
typeof function(){} === 'function';
typeof Math.sin === 'function';
typeof null === 'object'; // 從JavaScript誕生以來,一直是這樣的.
6.三元運算符 :強大且風騷
語法
expression ? xxx : yyy
bad
var direction;
if(x < 200){
direction = 1;
} else {
direction = -1;
}
good
var direction = x < 200 ? 1 : -1;
7.使用邏輯 AND/OR 做條件判斷
var foo = 10; foo == 10 && doSomething(); // 等價於 if (foo == 10) doSomething(); foo == 5 || doSomething(); // 等價於 if (foo != 5) doSomething(); //默認值 a = b || 'default' return b || c || d > 1 ? 0 : 2
8.給一個變量賦值的時候不要忘記使用var關鍵字
給一個未定義的變量賦值會導致創建一個全局變量。要避免全局變量
9.自我調用的函數
自調用匿名函數(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)
10.避免使用 eval() 和 Function 構造函數
Eval=邪惡, 不僅大幅降低腳本的性能(譯注:JIT編譯器無法預知字符串內容,而無法預編譯和優化),而且這也會帶來巨大的安全風險,因為這樣付給要執行的文本太高的權限,避而遠之
使用 eval 和 Function 構造函數是非常昂貴的操作,因為每次他們都會調用腳本引擎將源代碼轉換成可執行代碼。
var func1 = new Function(functionCode); var func2 = eval(functionCode);
11.避免使用 with()
使用 with() 會插入一個全局變量。因此,同名的變量會被覆蓋值而引起不必要的麻煩
12.腳本放在頁面的底部
記住——首要目標是讓頁面盡可能快的呈獻給用戶,腳本的夾在是阻塞的,腳本加載並執行完之前,浏覽器不能繼續渲染下面的內容。因此,用戶將被迫等待更長時間
13.避免在For語句內聲明變量
bad
for(var i = 0; i < someArray.length; i++) {
var container = document.getElementById('container');
container.innerHtml += 'my number: ' + i;
console.log(i);
}
good
var container = document.getElementById('container');
for(var i = 0, len = someArray.length; i < len; i++) {
container.innerHtml += 'my number: ' + i;
console.log(i);
}
14.給代碼添加注釋
// 循環數組,輸出每項名字(譯者注:這樣的注釋似乎有點多余吧).
for(var i = 0, len = array.length; i < len; i++) {
console.log(array[i]);
}
15.instanceof
instanceof 方法要求開發者明確地確認對象為某特定類型
var oStringObject = new String("hello world");
console.log(oStringObject instanceof String); // 輸出 "true"
// 判斷 foo 是否是 Foo 類的實例
function Foo(){}
var foo = new Foo();
console.log(foo instanceof Foo)//true
// 判斷 foo 是否是 Foo 類的實例 , 並且是否是其父類型的實例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo();//JavaScript 原型繼承
var foo = new Foo();
console.log(foo instanceof Foo)//true
console.log(foo instanceof Aoo)//true
16.apply/call
someFn.call(this, arg1, arg2, arg3); someFn.apply(this, [arg1, arg2, arg3]);
apply
Function.apply(obj,args)方法能接收兩個參數
obj:這個對象將代替Function類裡this對象
args:這個是數組,它將作為參數傳給Function(args-->arguments)
call
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:這個對象將代替Function類裡this對象
params:這個是一個參數列表
使用哪個取決於參數的類型