JavaScript 編程精解 (3)

第三章 函數(shù)

  • 函數(shù)是JavaScript中不可或缺的組成部分
  • 函數(shù)是構(gòu)造大型程序的工具,可以用于減少重復(fù)性工作羡儿、為子程序命名并隔離各個(gè)子程序的運(yùn)行礼患。

3.1 定義函數(shù)

創(chuàng)建函數(shù)的表達(dá)式以關(guān)鍵字function開(kāi)頭。

var fun = function (parameter1, parameter2, ...) {//參數(shù)可以為空掠归,也可以為一或多個(gè)
    // 函數(shù)體缅叠,哪怕只有一條語(yǔ)句,也要包含在大括號(hào)中虏冻,語(yǔ)句會(huì)在調(diào)用函數(shù)時(shí)執(zhí)行
    ...
    // return語(yǔ)句決定了函數(shù)的返回值肤粱,后面不跟表達(dá)式時(shí)返回undefined
    return;
}

3.2 參數(shù)和作用域

  • 函數(shù)的參數(shù)初始值由函數(shù)調(diào)用者提供。

  • 函數(shù)內(nèi)部創(chuàng)建的變量和參數(shù)都屬于函數(shù)的局部變量厨相,這種隔離機(jī)制確保了函數(shù)間不會(huì)相互干擾领曼。

3.3 嵌套作用域

  • 可以在函數(shù)中創(chuàng)建其他函數(shù),并產(chǎn)生不同程度的局部作用域蛮穿。

  • 任何局部作用域都可以訪問(wèn)到包含它的局部作用域

  • 函數(shù)內(nèi)部變量的可見(jiàn)性取決于函數(shù)在代碼當(dāng)中的位置庶骄,在包含了一個(gè)函數(shù)定義的代碼塊中,這個(gè)函數(shù)可以訪問(wèn)到代碼塊中的所有變量践磅,即函數(shù)上層的代碼塊中的變量和函數(shù)內(nèi)部的變量单刁。這種控制變量的方法稱為詞法作用域

  • let關(guān)鍵字作用與var相同府适,只不過(guò)變量作用域是塊作用域而非函數(shù)局部作用域羔飞。

3.4 函數(shù)值

函數(shù)和函數(shù)名的區(qū)別函數(shù)是一種叫做function引用類型的實(shí)例肺樟,因此函數(shù)是一個(gè)對(duì)象。對(duì)象是保存在內(nèi)存中的褥傍,函數(shù)名則是指向這個(gè)對(duì)象的指針儡嘶。

JavaScript中函數(shù)是一等公民喇聊,可以作為參數(shù)傳入別的函數(shù)恍风,也可以作為一個(gè)函數(shù)的返回值,也可以被重新賦值誓篱。

3.5 符號(hào)聲明

函數(shù)聲明還有一種更為簡(jiǎn)潔的方式:

function fun(parameter) {
    //todo
}
  • 函數(shù)聲明不遵循一般的從上到下的流控制規(guī)則朋贬。
console.log('are you ok ?', ans());

function ans() {
    return 'yeah, i\'m ok';
}
  • 為了確保函數(shù)在不同環(huán)境下運(yùn)行的行為一致,應(yīng)在最外層的函數(shù)或程序作用域中進(jìn)行函數(shù)聲明窜骄。

3.6 調(diào)用棧

由于函數(shù)需要在執(zhí)行結(jié)束后跳轉(zhuǎn)回調(diào)用該函數(shù)的代碼位置锦募,因此計(jì)算機(jī)必須記住函數(shù)調(diào)用的上下文。我們將計(jì)算機(jī)存儲(chǔ)這個(gè)上下文的區(qū)域稱之為調(diào)用棧邻遏。

  • 當(dāng)函數(shù)調(diào)用時(shí)糠亩,當(dāng)前的上下文信息就會(huì)被存儲(chǔ)在棧頂

  • 當(dāng)函數(shù)返回時(shí),系統(tǒng)會(huì)刪除存儲(chǔ)在棧頂?shù)纳舷挛男畔⒆佳椋⑹褂迷撔畔⒗^續(xù)執(zhí)行程序赎线。

// 若計(jì)算機(jī)空間無(wú)限大,循環(huán)調(diào)用會(huì)一直執(zhí)行下去糊饱,但事實(shí)上是該程序會(huì)耗盡內(nèi)存空間垂寥,導(dǎo)致“棧空間溢出”另锋。
function chicken() {
    return egg();
}
function egg() {
    return chicken();
}
console.log(chicken() + ' came first.');

3.7 可選參數(shù)

JavaScript對(duì)傳送函數(shù)的參數(shù)數(shù)量幾乎不做任何限制滞项。如果你傳遞了過(guò)多參數(shù),多余的參數(shù)就會(huì)被忽略夭坪,而如果你傳遞的參數(shù)過(guò)少文判,遺漏的參數(shù)將會(huì)被賦值成undefined。

缺點(diǎn):你可能恰好向函數(shù)傳遞了錯(cuò)誤數(shù)量的參數(shù)室梅,但沒(méi)有人會(huì)告訴你這個(gè)錯(cuò)誤律杠。

優(yōu)點(diǎn): 我們可以利用這種行為來(lái)讓函數(shù)接收可選參數(shù)。

3.8 閉包

如果函數(shù)已經(jīng)執(zhí)行結(jié)束竞惋,那么這些由函數(shù)創(chuàng)建的局部變量會(huì)如何處理呢柜去?

function wrapValue(n) {
    var localVariable = n;
    return function { return localVariable; };
}
var wrap1 = wrapValue(1);
var wrap2 = wrapValue(2);
console.log(wrap1());
// 1
console.log(wrap2());
// 2

這段代碼很好地印證了局部變量會(huì)在每次函數(shù)調(diào)用時(shí)重新創(chuàng)建,不同的函數(shù)調(diào)用是不會(huì)對(duì)其他函數(shù)內(nèi)的局部變量產(chǎn)生影響的拆宛。

這種引用特定的局部變量實(shí)例的功能稱為閉包嗓奢。一個(gè)包裝了一些局部變量的函數(shù)是一個(gè)閉包。利用閉包的特性浑厚,我們不再需要擔(dān)心變量的生命周期問(wèn)題股耽,很多高級(jí)應(yīng)用都依靠它來(lái)實(shí)現(xiàn)根盒。

function multiplier(factor) {
    return function(number) {
        return number * factor;
    }
}

var twice = multiplier(2);
console.log(twice(5));
//10

可以把關(guān)鍵字function當(dāng)做一種“凍結(jié)”代碼并將其打包成函數(shù)值的模型。所以當(dāng)看到“return function(...) {...}”這樣的代碼時(shí)物蝙,可以將其理解為一個(gè)句柄炎滞,其中句柄指向一段包裝好的計(jì)算代碼。

3.9 遞歸

函數(shù)完全可以自己調(diào)用自己诬乞,只要避免棧溢出的問(wèn)題即可册赛。我們把函數(shù)調(diào)用自身的行為稱為遞歸

function power(base, exponent) {
    if (exponent == 0)
      return 1;
    else
      return base * power(base, exponent-1);
}

console.log(power(2, 3));
// 8

需要注意的是震嫉,在標(biāo)準(zhǔn)的JavaScript實(shí)現(xiàn)當(dāng)中森瘪,遞歸寫(xiě)法的函數(shù)執(zhí)行效率比循環(huán)寫(xiě)法的函數(shù)慢了大約10倍。如何權(quán)衡性能與優(yōu)雅是一個(gè)值得考慮的問(wèn)題票堵,但有一條基本原則:除非程序執(zhí)行速度確實(shí)太慢扼睬,否則先不要關(guān)注效率問(wèn)題。

對(duì)于某些問(wèn)題來(lái)說(shuō)悴势,遞歸相較于循環(huán)更能解決問(wèn)題窗宇。這類問(wèn)題通常需要執(zhí)行和處理多個(gè)分支,而每個(gè)分支又會(huì)引出更多的執(zhí)行分支特纤。

3.10 添加新函數(shù)

兩種常用的引入函數(shù)的方法:

  1. 找出程序中多次出現(xiàn)的相似代碼质蕉。

  2. 寫(xiě)新功能代碼橱野,覺(jué)得一些代碼應(yīng)該包含在一個(gè)函數(shù)時(shí)媒抠。甚至可以先編寫(xiě)調(diào)用函數(shù)的代碼爸邢,然后再具體實(shí)現(xiàn)調(diào)用的函數(shù)。

給函數(shù)起名的難易程度取決于我們封裝的函數(shù)的用途是否明確矗蕊。

3.11 函數(shù)及其副作用

可以將函數(shù)分為兩類:一類調(diào)用后產(chǎn)生副作用短蜕,而另一類則產(chǎn)生返回值(當(dāng)然也可以定義同時(shí)產(chǎn)生副作用和返回值的函數(shù))。

相比于直接產(chǎn)生副作用的函數(shù)傻咖,產(chǎn)生返回值的函數(shù)更容易集成到新的環(huán)境當(dāng)中使用朋魔。但在副作用的幫助下,有些操作則更易卿操、更快實(shí)現(xiàn)警检,因此考慮到運(yùn)算速度,有時(shí)候純函數(shù)并不可取害淤。

3.12 本章小結(jié)

  1. 對(duì)于關(guān)鍵字function來(lái)說(shuō)扇雕,當(dāng)我們將其作為表達(dá)式來(lái)使用的時(shí)候,可以創(chuàng)建一個(gè)函數(shù)值窥摄。當(dāng)我們將其作為語(yǔ)句來(lái)使用的時(shí)候镶奉,可以用來(lái)聲明并將函數(shù)賦予變量。
// Create a function value f
var f = function(a) {
    console.log(a + 2);
}

// Declare g to be a function
function g(a, b) {
    return a * b * 3.5;
}
  1. 要理解函數(shù)的含義,就必須理解局部作用域的概念哨苛。對(duì)于一個(gè)函數(shù)來(lái)說(shuō)鸽凶,其參數(shù)及其內(nèi)部聲明的變量都是局部變量,每當(dāng)調(diào)用函數(shù)時(shí)建峭,這些變量都會(huì)被重新創(chuàng)建玻侥,而且對(duì)外并不可見(jiàn)。而在函數(shù)作用域當(dāng)中聲明的函數(shù)亿蒸,可以訪問(wèn)其外部函數(shù)的局部作用域凑兰。

  2. 將程序中的任務(wù)劃分到不同的函數(shù)中的做法是非常有用的,而且有助于提高代碼的可讀性祝懂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末票摇,一起剝皮案震驚了整個(gè)濱河市拘鞋,隨后出現(xiàn)的幾起案子砚蓬,更是在濱河造成了極大的恐慌,老刑警劉巖盆色,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灰蛙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡隔躲,警方通過(guò)查閱死者的電腦和手機(jī)摩梧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宣旱,“玉大人仅父,你說(shuō)我怎么就攤上這事』胍鳎” “怎么了笙纤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)组力。 經(jīng)常有香客問(wèn)我省容,道長(zhǎng),這世上最難降的妖魔是什么燎字? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任腥椒,我火速辦了婚禮,結(jié)果婚禮上候衍,老公的妹妹穿的比我還像新娘笼蛛。我一直安慰自己,他們只是感情好蛉鹿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布滨砍。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪惨好。 梳的紋絲不亂的頭發(fā)上煌茴,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音日川,去河邊找鬼蔓腐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛龄句,可吹牛的內(nèi)容都是我干的回论。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼分歇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼傀蓉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起职抡,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤葬燎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后缚甩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谱净,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年擅威,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壕探。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郊丛,死狀恐怖李请,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厉熟,我是刑警寧澤导盅,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站庆猫,受9級(jí)特大地震影響认轨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜月培,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一嘁字、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杉畜,春花似錦纪蜒、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春猬错,著一層夾襖步出監(jiān)牢的瞬間窗看,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工倦炒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留显沈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓逢唤,卻偏偏與公主長(zhǎng)得像拉讯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鳖藕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 人生苦多魔慷,快來(lái) Kotlin ,快速學(xué)習(xí)Kotlin著恩! 什么是Kotlin院尔? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,145評(píng)論 9 118
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法页滚,內(nèi)部類的語(yǔ)法召边,繼承相關(guān)的語(yǔ)法铺呵,異常的語(yǔ)法裹驰,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,581評(píng)論 18 399
  • 與寶寶飯后去買了一本新的note book幻林。不知不覺(jué)中他終于完成了第一本日記本。說(shuō)是日記音念,也不完全是沪饺,不一定是每天...
    無(wú)擔(dān)閱讀 236評(píng)論 0 0
  • 我發(fā)現(xiàn)每每迷茫的時(shí)候整葡,總是玩手機(jī)到深夜,還常常找成人網(wǎng)站讥脐,看完就睡不著了遭居,你有過(guò)嗎? 為了音樂(lè)夢(mèng)旬渠,我找了間一個(gè)月2...
    楊嘯嘯閱讀 194評(píng)論 0 0
  • 交績(jī)五系統(tǒng)當(dāng)中的中心圓始終是目標(biāo)俱萍,而在《刻意練習(xí)》這本書(shū)中也提到了目標(biāo)對(duì)于刻意訓(xùn)練的重要性,‘目標(biāo)’對(duì)于學(xué)習(xí)力的提...
    多瀚Sean閱讀 111評(píng)論 0 0