国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

深入理解JavaScript系列(1)

2018-06-09 15:51 更新

本文是深入理解JavaScript系列的第篇讀文筆記,博客原文在這里。

內(nèi)容簡要

本文是湯姆大叔《JavaScript Patterns》的基礎(chǔ)上,可能參考了一些其他的文章,寫成的一篇最佳實(shí)踐Style文章。全文緊扣如何編寫高質(zhì)量JavaScript代碼這一問題,通過羅列一系列points來闡述哪些是推薦做的,哪些是不推薦做的。

BACKBONE

書寫可維護(hù)的代碼

bug是應(yīng)用程序的天敵,在現(xiàn)實(shí)世界中,沒有應(yīng)用程序是沒有bug的。但是bug的修復(fù)成本往往是比較昂貴的。故,為了降低修復(fù)bug的成本,書寫維護(hù)性高的代碼是及其有意義的。

那么,可維護(hù)的代碼應(yīng)該包括哪些基本要素呢?

  • 可讀的
    我們不推薦在代碼中使用過多的hack style的技巧,以及過多的復(fù)雜判斷或者其他邏輯等。因?yàn)檫@會(huì)讓后續(xù)的維護(hù)者花費(fèi)更多的時(shí)間去理解代碼。
  • 一致的
    代碼應(yīng)該在空間和行為上具有一致性。
  • 可預(yù)測的
    可預(yù)測的含義比較廣,比如,應(yīng)該把相似的邏輯放在一起,讓維護(hù)者可以預(yù)測你代碼的組織結(jié)構(gòu)。
  • 看上去像是同一個(gè)人寫的
    這一點(diǎn)比較好理解。同一份代碼中,所有的參與者都應(yīng)該遵循同一份code style。
  • 已記錄
    這里的已記錄我個(gè)人猜測的含義應(yīng)該是在適當(dāng)?shù)牡胤綉?yīng)該有明確的注釋,并且在復(fù)雜邏輯出應(yīng)該注明邏輯實(shí)現(xiàn)思想。

最小全局變量

JavaScript語言通過函數(shù)來管理作用域。在函數(shù)內(nèi)部聲明的變量只能在這個(gè)函數(shù)的內(nèi)部使用,外部不可用。另一方面,全局變量指在函數(shù)外部聲明的變量,或者未聲明就直接使用的變量(我們一般不推薦這種做法,因?yàn)榭赡軙?huì)導(dǎo)致各種意想不到的問題。)。

就一般而言,我們指的全局變量都是指瀏覽器環(huán)境,往往就是指window這個(gè)對(duì)象。

全局變量的問題

JavaScript中全局變量導(dǎo)致的問題最常見的就是命名沖突。比如你先引入了JQuery,然后又自己定義了一個(gè)全局變量$,明顯的,JQuery$變量就被你覆蓋了。

一般而言,我們推薦盡量少的使用全局變量,可以通過命名空間或者自執(zhí)行函數(shù)來減少命名空間的使用。

全局變量還有另外一個(gè)常見的問題,就是不通過var關(guān)鍵字聲明的變量,都將隱式的轉(zhuǎn)變成全局變量。所以我們推薦所有的變量都使用var關(guān)鍵字進(jìn)行聲明。

另一個(gè)創(chuàng)建隱式全局變量的反例就是使用任務(wù)鏈進(jìn)行部分var聲明。如下代碼,

function foo() {
    var a = b = 0;
    // ...
}

這里,變量b將會(huì)被隱式轉(zhuǎn)換為全局變量。此現(xiàn)象發(fā)生的原因在于JavaScript使用從右到左的賦值。

首先,是賦值表達(dá)式b = 0,此情況下b是未聲明的。這個(gè)表達(dá)式的返回值是0,然后這個(gè)0就分配給了通過var定義的局部變量a。換句話說,相當(dāng)于你輸入了,

var a = (b = 0);

所以,當(dāng)需要進(jìn)行一次性進(jìn)行多個(gè)變量賦值時(shí),我們一般推薦如下的做法,

function foo() {
    var a, b;
    // ...
}

忘記var的副作用

隱式的全局變量和明確定義的全局變量間有些小的差異,就是能否通過delete操作符讓變量未定義的能力。

  • 通過var創(chuàng)建的全局變量是不能被刪除的。
  • var創(chuàng)建的隱式全局變量是能被刪除的。(被刪除后,變量的值變?yōu)?code>undefined)

這點(diǎn)說明了什么問題呢?

在技術(shù)上,隱式全局變量并不是真正的全局變量,但他們是全局變量的屬性。而屬性是可以通過delete操作符刪除的,而變量是不可以的。

現(xiàn)在ES5的strict模式下,未聲明的變量工作時(shí)拋出一個(gè)錯(cuò)誤。

ps:這點(diǎn)老實(shí)說,之前我也不知道。:(

單var形式

在函數(shù)頂部使用單var語句是比較有用的一種形式,其好處在于,

  • 提供了一個(gè)單一的地方去尋找功能所需要的所有局部變量
  • 防止變量在定義之前使用
  • 幫助你記住聲明的全局變量
  • 減少代碼量
  • 利于壓縮工具的壓縮

var形式長得就像下面的這個(gè)樣子,

function foo() {
    var a = 1,
        b = 2,
        sum = a + b,
        myobject = {},
        i,
        j;
    // more code...
}

這種單var形式的變量聲明好處多多,但是有一個(gè)不好的地方就是不利于調(diào)試。因?yàn)檎{(diào)試時(shí),單步就直接把var語句執(zhí)行完畢了,這樣你可能就看不到類似sum = a + b這種運(yùn)算表達(dá)式的細(xì)節(jié)了。

預(yù)解析

在JavaScript中,你可以在函數(shù)的任意位置進(jìn)行var語句聲明,并且他們就好象是在函數(shù)頂部聲明一樣發(fā)揮作用。這種行為稱為hoisting(懸置/置頂解析/預(yù)解析)。

當(dāng)你使用了一個(gè)變量,然后不久在函數(shù)中又重新聲明的話,就可能產(chǎn)生邏輯錯(cuò)誤。對(duì)于JavaScript,只要你的變量是在同一個(gè)作用域中(同一函數(shù)),它都被當(dāng)做是聲明的,即使是它是在var聲明前使用的。

ps:我本人以前就踩過這種坑!

讓我們來看一個(gè)例子,

// 反例
myname = "global"; // 全局變量
function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
}
func();

在這個(gè)例子中,你可能會(huì)以為第一個(gè)alert彈出的是global,第二個(gè)彈出loacl。這種期許是可以理解的,因?yàn)樵诘谝粋€(gè)alert的時(shí)候,myname未聲明,此時(shí)函數(shù)肯定很自然而然地看全局變量myname,但是,實(shí)際上并不是這么工作的。第一個(gè)alert會(huì)彈 出undefined是因?yàn)?code>myname被當(dāng)做了函數(shù)的局部變量(盡管是之后聲明的),所有的變量聲明都被懸置到函數(shù)的頂部了。

因此,為了避免這種混亂,最好是預(yù)先聲明你想使用的全部變量。

ps:大叔的解釋已經(jīng)夠好了,我就直接引用了,沒必要畫蛇添足了。

其實(shí),上面的代碼就等同于下面,

myname = "global"; // global variable
function func() {
    var myname; // 等同于 -> var myname = undefined;
    alert(myname); // "undefined"
    myname = "local";
    alert(myname); // "local"
}
func();

for循環(huán)

在for循環(huán)中,你可以循環(huán)取得數(shù)組或是數(shù)組類似對(duì)象的值,譬如argumentsHTMLCollection對(duì)象。通常的循環(huán)形式如下,

// 次佳的循環(huán)
for (var i = 0; i < myarray.length; i++) {
    // 使用myarray[i]做點(diǎn)什么
}

這種形式的循環(huán)的不足在于每次循環(huán)的時(shí)候數(shù)組的長度都要去獲取下。這回降低你的代碼,尤其當(dāng)myarray不是數(shù)組,而是一個(gè)array-like對(duì)象的時(shí)候。

一般我們會(huì)采取緩存數(shù)組的長度這種方式來進(jìn)行循環(huán)遍歷,

for (var i = 0, max = myarray.length; i < max; i++) {
    // 使用myarray[i]做點(diǎn)什么
}

這樣,在這個(gè)循環(huán)過程中,你只檢索了一次長度值。

for-in循環(huán)

for-in循環(huán)應(yīng)該用在非數(shù)組對(duì)象的遍歷上,使用for-in進(jìn)行循環(huán)也被稱為枚舉。

for-in循環(huán)有兩點(diǎn)需要提一下,

  • 盡量不要使用for-in去遍歷數(shù)組對(duì)象
  • 使用hasOwnProperty方法可以過濾掉來自原型上的屬性和方法

擴(kuò)展內(nèi)置原型

在許久之前,有一個(gè)流行的JavaScript類庫叫做Prototype,他就是擴(kuò)展了原生對(duì)象的原型(我不明確現(xiàn)在是不是還是這樣的:(,因?yàn)槲易约阂矝]用過這個(gè)類庫)。

不過,現(xiàn)在業(yè)內(nèi)基本都已經(jīng)達(dá)成共識(shí),不推薦(或者不允許)擴(kuò)展原生對(duì)象的原型。因?yàn)檫@在多人合作或者大型項(xiàng)目造成諸多問題。

如果你嫌棄原生對(duì)象沒有提供足夠的方法,推薦你使用下面兩款工具類庫,

如果上面的工具庫還不能滿足你,你可以自己實(shí)現(xiàn)需要工具方法,但是請記住,不要掛載在原生對(duì)象的原型上!。

避免隱式類型轉(zhuǎn)換

JavaScript是一門弱語言編程語言,他有一個(gè)強(qiáng)大的功能就是隱式類型自動(dòng)轉(zhuǎn)換。這個(gè)功能有時(shí)間太強(qiáng)大了,會(huì)在你不知道的情況下進(jìn)行類型轉(zhuǎn)換,然后引起一些問題和混亂。

比如下面的例子,

var a = '11',
    b = 11,
    c = a + b;
console.log(c);

這里c的結(jié)果將會(huì)是1111,他是一個(gè)字符串??赡苓@種情況并不是你的本意。

另一方面,特別是在進(jìn)行條件判斷的時(shí)候,我們更推薦使用===!==,而不是==!=。

避免使用eval和with

我相信,大部分寫JavaScript的程序員甚至很少接觸到這兩個(gè)東西,甚至都沒聽說過(哈哈,有點(diǎn)夸張了)。先簡單說下evalwith的作用。

  • eval()的作用是,接受一個(gè)字符串,將此字符串當(dāng)作JavaScript代碼來處理
  • with(){}的作用是,指定{}內(nèi)代碼的this指向

eval在特定的情況下可能會(huì)比較有用一點(diǎn),比如進(jìn)行一些內(nèi)庫開發(fā)的時(shí)候,但是with的使用真的很少,基本上都是不推薦使用的。

這里我簡單的說一下使用eval可能會(huì)出現(xiàn)的幾個(gè)問題,

  • 存在安全隱患
    因?yàn)?code>eval將接受到的字符串當(dāng)作JavaScript代碼來處理。如果接受到的字符串本身存在安全問題(比如來自網(wǎng)絡(luò)請求得到的),那么執(zhí)行這條字符串可能造成安全風(fēng)險(xiǎn)。
  • 污染當(dāng)前作用域
    eval執(zhí)行時(shí),其內(nèi)部使用的作用域是全局作用域。如果你在內(nèi)部定義了一個(gè)變量與全局變量名一致,那么就會(huì)覆蓋之前的全局變量。

使用parseInt()進(jìn)行數(shù)值轉(zhuǎn)換

parseInt是原生提供一個(gè)用于解析數(shù)字的工具方法。他接受一個(gè)字符串,將字符串中數(shù)字解析成數(shù)值型,如果遇到非數(shù)字型字符串,則解析過程停止。該函數(shù)還可以接受第二個(gè)參數(shù),表示數(shù)值的基數(shù)。

這里就簡單的說一下使用parseInt應(yīng)該注意的幾個(gè)方面,

  • 盡量傳入第二個(gè)參數(shù)
    通過的用法中都省略了第二個(gè)基數(shù)參數(shù),其實(shí)這是不應(yīng)該的。比如,如果我傳入的字符串為099這種,而且沒有傳入基數(shù)參數(shù),那么這個(gè)099將會(huì)被當(dāng)作八進(jìn)制數(shù)來處理,這明顯與我的本意相違背。

編碼規(guī)范相關(guān)

大叔這里還提了一下編碼規(guī)范相關(guān)的內(nèi)容。關(guān)于code style這個(gè)東西,我個(gè)人的看法是遵循一般性原則,細(xì)節(jié)適時(shí)調(diào)整即可。

比如說我個(gè)人的code style,我大致參考的是Google JavaScript Style Guide,當(dāng)然也不是完全100%的照搬,我也會(huì)做一些適當(dāng)?shù)恼{(diào)整。比如,google js style中說空格使用2個(gè)空格,但是我個(gè)人習(xí)慣使用4個(gè)空格。所以說,code style這東西不必太較真,就個(gè)人來說有個(gè)大致的參考即可;就公司團(tuán)隊(duì)來說,務(wù)必有一套人人都得遵守的規(guī)范,這是高質(zhì)量、高可維護(hù)代碼的基石之一。

這里,我僅羅列一下大叔提到的code style points,并不作具體說明,

  • 縮進(jìn)(Indentation)
  • 花括號(hào)(Curly Braces)
  • 花括號(hào)的位置(Opening Brace Location)
  • 空格(White Space)
  • 命名規(guī)范(Naming Conventions)
  • 以大寫字段寫構(gòu)造函數(shù)(Capitalizing Constructors)
  • 分割單詞(Separating Words)
  • 其他命名形式(Other Naming Patterns)
  • 注釋(Writing Comments)

這里,打個(gè)小廣告,我個(gè)人code style的repo。

總結(jié)

如何編寫高質(zhì)量的JavaScript代碼?

ps:以下都是個(gè)人觀點(diǎn)

一句話可以概括,把握語言本質(zhì),較真語言細(xì)節(jié),輔以實(shí)踐經(jīng)驗(yàn)。

說的簡單通俗點(diǎn),就是


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)