小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Javascript 優(yōu)化項(xiàng)目代碼技巧之語(yǔ)言基礎(chǔ)(一)

 quasiceo 2018-08-18

    Javascript的弱類型以及函數(shù)作用域等規(guī)則使用編寫Javascript代碼極為容易,但是編寫可維護(hù)、高質(zhì)量的代碼卻變得十分困難,這個(gè)系列的文章將總結(jié)在項(xiàng)目開發(fā)過程中,能夠改善代碼可讀性、可維護(hù)性及優(yōu)化運(yùn)行性能的一系列技巧。
    如有問題,請(qǐng)不吝指出,非常感謝;如果喜歡,右下角點(diǎn)個(gè)推薦吧~

1.全局變量污染與變量提升

  • 定義全局變量的3種方式
var key = 'value'; // 所有函數(shù)外執(zhí)行
window.key = 'value'; // window為全局對(duì)象
key = 'value'; // 省去 var,隱式的全局變量
  • 全局對(duì)象是所有域中都可見的變量,如果程序比較小,那么定義全局變量可以避免函數(shù)調(diào)用時(shí)參數(shù)的傳遞,但是對(duì)于一個(gè)大的項(xiàng)目,全局變量定義不善,極為容易造成全局變量被某個(gè)程序改掉,而沒有被發(fā)現(xiàn),這也使調(diào)試時(shí)難以發(fā)現(xiàn)問題所在。
  • 在項(xiàng)目較大時(shí),建議盡可能地避免使用全局變量,那么兼顧靈活性與可讀性的解決方法就是在程序中只創(chuàng)建一個(gè)全局變量。
/** 
 * 只有Person一個(gè)全局變量,
 * 其余變量定義在Person下,盡可能地避免與其他變量名沖突
 */
var Person = { name:"A", age:20 };
Person.parents = {
    father:"A",
    mother:"C"
}
Person.getAge = function() { /* ... */ }
  • 與C、Python等語(yǔ)言擁有塊級(jí)作用域不同,Javascript作用域是以函數(shù)為單位的,定義在函數(shù)中的變量函數(shù)外部不可見,但是在函數(shù)內(nèi)部(包括其子函數(shù))處處可見。
/**
 * 考慮下面的函數(shù),先運(yùn)行f1(),再var b = 4,
 * 但是事實(shí)上,f1()中的b就是之后定義的b
 * 這是變量提升特性造成的,就是說所有變量定義都將提到函數(shù)最前面
 * 局部變量的優(yōu)先級(jí)高于外部變量,因此f()外部的b至始至終沒有變過
 */
var b = 15;
var f = function() { 
    var a = 100;
    var f1 = function(){
        var c = 3;
        b = a + c;  // => b=103 變量提升,這里的b是函數(shù)f()內(nèi)部的b
    };
    f1(); 
    var b = 4;
    console.log(a , b , c); // => a=100,b=4,c=undefined
}
f();  
console.log(b); // => b=15,b并沒有發(fā)生改變

2.數(shù)據(jù)類型

  • 浮點(diǎn)數(shù)是不精確的,在項(xiàng)目中,特別是在線支付環(huán)節(jié),如果希望計(jì)算的結(jié)果是準(zhǔn)確的,一般先乘100轉(zhuǎn)換為整數(shù)后,計(jì)算完后再除以100,這樣能夠得到預(yù)想中的結(jié)果。
0.1 + 0.2 === 0.3 // => false
  • 檢測(cè)數(shù)據(jù)類型,我們先看面試中常出現(xiàn)的判斷題
typeof null === 'null' // => false
typeof null === 'object' // => true
typeof NaN === 'NaN'  // => false
typeof NaN === 'number' // => true
// javascript6個(gè)基本類型如下,typeof總是返回這6個(gè)值
// number、string、boolean、object、function、undefined
// chrome 50中,typeof 3/0 結(jié)果為 NaN,有博友知道為什么求告知
  • typeof null 返回的是'object',項(xiàng)目開發(fā)中,我們并不希望null被判斷為'object',自定義一個(gè)函數(shù),可以滿足需求。
function type(ob){
    return (ob === null ) ? "null" : (typeof ob);
}
  • 上面的方法不能識(shí)別數(shù)組、日期等對(duì)象,如果需要判斷日期、數(shù)組、正則、錯(cuò)誤等類型,那么可以考慮使用toString()方法。
// 更多內(nèi)置類型,例如 Math 等可以根據(jù)需要添加
function type(ob){
    var _toString = Object.prototype.toString;
    var _type = {
        "undefined" : "undefined",
        "number" : "number",
        "boolean" : "boolean",
        "string" : "string",
        "[object Function]" : "function",
        "[object RegExp]" : "regexp",
        "[object Array]" : "array",
        "[object Date]" : "date",
        "[object Error]" : "error"
    }
    return _type[typeof ob] || _type[_toString.call(ob)] || (ob ? "object" : "null");
}
  • 自定義類型,可結(jié)合typeof、constructor屬性和instanceof實(shí)現(xiàn)

3.特殊值(NaN、undefined、null)

typeof NaN === 'number' // => true 類型為number,表示非數(shù)字
'0.1223' // => 0.1223
'1e6' // => 1000000
'1a3' // => NaN
1.2 + NaN // => NaN
  • Javascript提供了isNaN函數(shù)檢測(cè)NaN值
// 不能轉(zhuǎn)換為數(shù)字的值,均返回true,
// 因此并不能用這個(gè)函數(shù)檢測(cè)一個(gè)值是否真的為 NaN
isNaN(NaN) // => true
isNaN('abc') // => true
isNaN(0)  // => false
isNaN('1e6') // => false
isNaN(3/0) // => fasle

// NaN是一個(gè)唯一自己與自己不相等的值
NaN === NaN // false 
NaN !== NaN // true
  • 如何檢查一個(gè)值是不是真的NaN
// 方法一
function _isNaN(value){
    return value !== value;
}
// 方法二
function _isNaN(value) {
    return typeof value === 'number' && isNaN(value);
}
  • 使用isFinite檢查是否可以是個(gè)數(shù)或可被轉(zhuǎn)換為一個(gè)數(shù)
isNaN(3/0) // => fasle,雖然3/0 不能代表一個(gè)數(shù),但是isNaN不能識(shí)別
isFinite(3/0) // => false,isFinite能檢測(cè) NaN和正負(fù)無(wú)窮大
isFinite("234") // => true,isFinite 可以將參數(shù)轉(zhuǎn)換為數(shù)字
isFinite(true) // => true,可轉(zhuǎn)化為數(shù)字的字符串和布爾值返回true
  • 判斷參數(shù)是否真的是一個(gè)數(shù)字,而不是可轉(zhuǎn)換為數(shù)字的字符串等
// 加一個(gè)基本類型判斷就OK
function isNumber (value) {
    return typeof value === "number" && isFinite(value);
}
  • undefined有如下幾種情況

    (1) 定義了變量但沒有賦值 var cc; cc === undefined // => true (2) 獲取一個(gè)對(duì)象不存在的屬性 (3) 沒有返回值的函數(shù),new + 構(gòu)造函數(shù)除外

    (4) 定義函數(shù)時(shí)聲明多個(gè)形參,調(diào)用時(shí)傳入?yún)?shù)個(gè)數(shù)少于聲明,多余的參數(shù)為undefined

  • null 只能顯示指定,一般用來清空對(duì)象
  • 0、NaN、''(空字符串)、false、null、undefined的布爾值為false(注意,[](空數(shù)組),{}(空對(duì)象)布爾值為 true )

var a = 4 ;
if({})a++; // => a=5 空對(duì)象可通過 Object.keys().length判斷
if([])a++; // => a=6 空數(shù)組通過 length 判斷

4. === 與 ==

  • 使用 == 比較前如果不是相同類型的值,將進(jìn)行類型轉(zhuǎn)換,轉(zhuǎn)換規(guī)則請(qǐng)看下面的例子。
'' == 0  // => true,String與Number,將String轉(zhuǎn)為 Number
0 == '0' // => true,同上
'' == '0'// => false,2個(gè)都是字符串,因此直接比較
fasle == '0'  // => true,Boolean與其他,將Boolean轉(zhuǎn)為Number
true == '3'  // => false,同上
false == undefined // => false,同上,0與undefined不等
false == 'false'   // => false,同上
null == undefined // => true,null與undefined比較返回true
  • === ,如果類型不同,則直接返回false,類型相同再進(jìn)行比較。
  • == 與 != 將進(jìn)行隱式的類型轉(zhuǎn)換,轉(zhuǎn)換規(guī)則復(fù)雜,因此在實(shí)際的項(xiàng)目開發(fā)中,建議避免使用 == 與 !=,盡量使用 === 與 !==。

5.沒有真正的數(shù)組

  • 在Javascript中,數(shù)組也是對(duì)象,因此typeof的結(jié)果是object,如果需要判斷一個(gè)對(duì)象是不是數(shù)組,那么可以使用第2部分的toString()方法,當(dāng)然還可以利用構(gòu)造函數(shù)判斷。
typeof value === 'object' && value.constructor === Array
  • 需要注意的是,函數(shù)參數(shù)arguments并不是數(shù)組,只是一個(gè)具有l(wèi)ength屬性,以數(shù)字作為鍵的對(duì)象,因此arguments不能使用數(shù)組的方法,但是利用上述方法仍將arguments判斷為數(shù)組。
  • 有時(shí)我們需要對(duì)arguments對(duì)象執(zhí)行數(shù)組的某些方法,這個(gè)時(shí)候可以利用下面的方法將arguments轉(zhuǎn)換為真數(shù)組
/* 將arguments對(duì)象轉(zhuǎn)換為數(shù)組 */
var args = Array.prototype.slice.call(arguments);
/* 具有l(wèi)ength屬性,鍵為數(shù)字且從0開始的對(duì)象 */
a = {0:"c",1:"d",length:2 }
Array.prototype.slice.call(a); // => ["c","d"]
/* 沒有l(wèi)ength屬性 */
a = {0:"c",1:"d"}
Array.prototype.slice.call(a); // => [ ] 空數(shù)組
/* 猜測(cè)slice方法實(shí)現(xiàn)方式 */function slice(ob){
    var arr = new Array(); 
    for(var i = 0; i < ob.length; i++ ){
        arr[i] == ob[i];
    }
    return arr;
}

6.避免使用with與eval

var ob = { a: 1, b: 2};
var d = 0;
with(ob){
    a = 3;  // ob.a = 3
    c = 4;  // ob.c = undefined,window.c = 4,無(wú)心聲明了全局變量
    d = 5;  // ob.d = undefined, d為with外申明的變量
}
  • 不推薦使用with的3個(gè)理由

    (1) 使用with時(shí),先檢查對(duì)象是否有該屬性,存在則使用,不存在則繼續(xù)查找作用域,會(huì)降低執(zhí)行性能
    (2) with語(yǔ)句中的變量語(yǔ)意不明確,可讀性差

    (3) 例如上例中的c不小心隱式聲明為全局變量,本意是給ob.c賦值,易出現(xiàn)問題且難以調(diào)試

  • 對(duì)于eval(),可以直接執(zhí)行一段js代碼,不推薦理由如下

    (1) eval需要將字符串解釋為代碼后執(zhí)行,降低執(zhí)行性能
    (2) eval降低程序的可讀性,例如 eval("var a = ob." + key)等價(jià)于var a=ob[key],后者明顯更優(yōu)

    (3) eval存在安全問題,任意傳入字符串都可能被解析執(zhí)行,惡意代碼也不例外

7.消除switch歧義

  • switch中的case語(yǔ)句,定義了函數(shù)的起點(diǎn),卻沒有定義函數(shù)的終點(diǎn),不要忘記case語(yǔ)句后使用break
  • 有時(shí)候,我們確實(shí)需要貫穿case語(yǔ)句,比如多種case情況,執(zhí)行同一個(gè)方法,這時(shí)候,建議顯式聲明,消除歧義
// 在需要貫穿的case語(yǔ)句后添加 /* empty */
// 避免檢查代碼時(shí)被認(rèn)為忘記寫了執(zhí)行語(yǔ)句
// 顯示申明,語(yǔ)意也更明確,提高可讀性
switch(a){
    case 1: /* empty */
    case 2:
        func1();
        break;
    case 3:
        func2();
        break;
}

8.不要省略塊標(biāo)志 { }

  • if、while、do、for等語(yǔ)句接受{ ... } 代碼塊,但是有時(shí)我們?cè)诖a塊中只有一行代碼,為了使代碼看起來簡(jiǎn)潔,很可能省略 { },但是這可能產(chǎn)生問題。
if(a)
    if(b)
        func1();
else
    func2();
// => 等價(jià)于
if(a)
    if(b)
        func1();
    else
        func2();
// 這并不是想要的結(jié)果,js不是python,還是加上大括號(hào)比較好
  • 加上括號(hào),也增強(qiáng)了代碼的可讀性,下面這種寫法是不是一目了然了呢
// 很清晰地看出 if(a) 和 else 并列
// if(b) 是 if(a) 的子語(yǔ)句
if(a){
    if(b){
        func1();
    }
}else{
    func2();

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多