摘要:函數(shù)表達(dá)式是中的一個(gè)既強(qiáng)大又容易令人困惑的特性。函數(shù)表達(dá)式有幾種不同的語(yǔ)法形式。匿名函數(shù)的屬性是空字符竄。在把函數(shù)當(dāng)成值使用的情況下,都可以使用匿名函數(shù)。不過(guò),這并不是匿名函數(shù)唯一的用途。不過(guò)我們可以使用命名函數(shù)表達(dá)式來(lái)達(dá)成相同的成果。
前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方翻譯的差強(qiáng)人意,所以用自己所理解的,嘗試解讀下。如有紕漏或錯(cuò)誤,會(huì)非常感謝您的指出。文中絕大部分內(nèi)容引用自《JavaScript高級(jí)程序設(shè)計(jì)第三版》。
函數(shù)表達(dá)式是JavaScript中的一個(gè)既強(qiáng)大又容易令人困惑的特性。
定義函數(shù)的方式有兩種: 一種是函數(shù)聲明,另外一種就是函數(shù)表達(dá)式。
函數(shù)聲明的語(yǔ)法是這樣的。
function functionName(arg0, arg1, arg2) { //函數(shù)體 }
語(yǔ)法:首先是function關(guān)鍵字,然后是函數(shù)的名字,這就是指定函數(shù)名的方式。
Firefox、Safari、Chrome和Opera都給函數(shù)定義了一個(gè)非標(biāo)準(zhǔn)的name屬性,通過(guò)這個(gè)屬性可以訪問(wèn)到給函數(shù)指定的名字。
這個(gè)屬性的值永遠(yuǎn)等于跟在function關(guān)鍵字后面的標(biāo)識(shí)符。
//只在Firefox、Safari、Chrome和Opera有效 function functionName(arg0, arg1, arg2) { } console.log(functionName.name); // "functionName"
關(guān)于函數(shù)聲明,它的一個(gè)重要特征就是函數(shù)聲明提升(function declaration hoisting),意思是在執(zhí)行代碼之前會(huì)先讀取函數(shù)聲明。這就意味著可以把函數(shù)聲明放在調(diào)用它的語(yǔ)句后面。
sayName(); // "Shaw" function sayName(){ console.log("Shaw"); }
這個(gè)例子不會(huì)拋出錯(cuò)誤,因?yàn)樵诖a執(zhí)行之前會(huì)先讀取函數(shù)聲明
第二種創(chuàng)建函數(shù)的方式是使用函數(shù)表達(dá)式。
函數(shù)表達(dá)式有幾種不同的語(yǔ)法形式。
下面是最常見(jiàn)的一種形式。
var functionName = function(arg0, arg1, arg2) { //functionBody };
這種形式看起來(lái)好像是常規(guī)的變量賦值語(yǔ)句,即創(chuàng)建一個(gè)函數(shù)并將它賦值給變量functionName。
這種情況下創(chuàng)建的函數(shù)叫做 匿名函數(shù)(anonymous function), 因?yàn)閒unction關(guān)鍵字后面沒(méi)有標(biāo)識(shí)符。
匿名函數(shù)也叫拉姆達(dá)函數(shù)。匿名函數(shù)的name屬性是空字符竄。
函數(shù)表達(dá)式與其他表達(dá)式一樣,在使用前必須先賦值。
sayHi(); // error : sayHi is not a function var sayHi = function(){ console.log("Hi"); } // var sayHi //此時(shí)sayHi是undefined // sayHi() // error : sayHi is not a function // sayHi = function() { console.log("Hi");}
理解函數(shù)提升的關(guān)鍵,就是理解函數(shù)聲明與函數(shù)表達(dá)式之間的區(qū)別。
能夠創(chuàng)建函數(shù)再賦值給變量,也就能夠把函數(shù)作為其他函數(shù)的值返回。
function createComparisonFunction(propertyName) { return function(object1, object2) { var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2) { return -1 }else if(value1 > value2) { return 1; } else { return 0; } } }
createComparisonFunction()返回了一個(gè)匿名函數(shù)。
返回的函數(shù)可能會(huì)被賦值給一個(gè)變量, 或者以其他方式被調(diào)用。
不過(guò),在createComparisonFunction()函數(shù)內(nèi)部,它是匿名的。
在把函數(shù)當(dāng)成值使用的情況下,都可以使用匿名函數(shù)。
不過(guò),這并不是匿名函數(shù)唯一的用途。
遞歸函數(shù)就是一個(gè)函數(shù)通過(guò)函數(shù)名調(diào)用自身的情況下構(gòu)成的。
function factorial(num) { if(num <= 1) { return 1; } else { return num * factorial(num-1); } } factorial(4); // 4*3*2*1 = 24 //4* factorial(3) => 4*3*factorial(2) => 4*3*2*factorial(1) => 4*3*2*1 => 24
這是一個(gè)經(jīng)典的遞歸階乘函數(shù)。雖然這個(gè)函數(shù)表面看來(lái)沒(méi)什么問(wèn)題,但下面的代碼卻可能導(dǎo)致它出錯(cuò)。
function factorial(num) { if(num <= 1) { return 1; } else { return num * factorial(num-1); } } var anotherFactorial = factorial; factorial = null; //注意這里,其實(shí)函數(shù)factorial指向一個(gè)空對(duì)象。 console.log(anotherFactorial(4)); //Error: anotherFactorial is not a function
以上代碼先把factorial()函數(shù)保存在變量anotherFactorial中,然后將factorial變量設(shè)置為null,結(jié)果指向原始函數(shù)的引用只剩下一個(gè)。
但在接下來(lái)調(diào)用anotherFactorial()時(shí),必須執(zhí)行factorial(),而factorial已經(jīng)不是函數(shù), 所以就會(huì)導(dǎo)致錯(cuò)誤。
Google Chrome測(cè)試了上述代碼,是不行的, 建議不用深入了解這部分的內(nèi)容。
在這種情況下,使用arguments.callee可以解決這個(gè)問(wèn)題。
arguments.callee是一個(gè)指向正在執(zhí)行的函數(shù)的指針,因此可以用它來(lái)實(shí)現(xiàn)對(duì)函數(shù)的遞歸調(diào)用。
function factorial(num) { if(num <= 1) { return 1; } else { return num * arguments.callee(num-1); } }
“return num * arguments.callee(num-1);” 通過(guò)使用arguments.callee代替函數(shù)名,可以確保無(wú)論怎么調(diào)用函數(shù)都不出問(wèn)題。
因此,在編寫遞歸函數(shù)時(shí),使用arguments.callee總比使用函數(shù)名更保險(xiǎn)。
但在嚴(yán)格模式下,不能通過(guò)腳本訪問(wèn)arguments.callee, 訪問(wèn)這個(gè)屬性會(huì)導(dǎo)致錯(cuò)誤。
不過(guò)我們可以使用命名函數(shù)表達(dá)式來(lái)達(dá)成相同的成果。
var factorial = function f(num){ if(num <= 1) { return 1; } else { return num * f(num-1); } } //factorial 指向了函數(shù)f var anotherFactorial = factorial; //anotherFactorial 指向了函數(shù)f factorial = null; //factorial 指向了一個(gè)空對(duì)象。 anotherFactorial(4); //24 ////anotherFactorial 指向了函數(shù)f, 所以還可以正常調(diào)用。
以上代碼創(chuàng)建了創(chuàng)建了一個(gè)名為f()的命名函數(shù)表達(dá)式,然后將它賦值給變量factorial。
即便把函數(shù)賦值給另一個(gè)變量,函數(shù)的名字f仍然有效,所以遞歸調(diào)用照樣能正確完成。
這種方式在嚴(yán)格模式和非嚴(yán)格模式下都行得通。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98684.html
摘要:組合子是演算中的一個(gè)概念,是任意函數(shù)的不動(dòng)點(diǎn),在函數(shù)式編程中主要作用是提供一種匿名函數(shù)的遞歸方式。組合子如下本文將盡量通俗易懂的以實(shí)現(xiàn)匿名函數(shù)遞歸為導(dǎo)向,推導(dǎo)出這一式子。若將替換為,將導(dǎo)致組合子中的作為的參數(shù)被立即求值。 Y 組合子是 lambda 演算中的一個(gè)概念,是任意函數(shù)的不動(dòng)點(diǎn),在函數(shù)式編程中主要作用是 提供一種匿名函數(shù)的遞歸方式。 Y 組合子如下: $$ λf.(λx.f(x...
摘要:布爾值,是否能通過(guò)循環(huán)或返回屬性。而區(qū)別在于為布爾值的特征的默認(rèn)值,通過(guò)屬性訪問(wèn)器設(shè)置的默認(rèn)都是,而通過(guò)定義屬性設(shè)置的默認(rèn)都是。該方法返回被凍結(jié)的對(duì)象。 可能很多人都知道最近很火的MVVM(model-view-virtualModel)框架,如Vue/Angular/React,如果你不知道的話,就要抓緊學(xué)習(xí)了,它能夠把你從高頻復(fù)雜的DOM解析中解脫出來(lái)。MVVM框架的最主要的特性就...
摘要:高階函數(shù)函數(shù)式編程中,接受函數(shù)作為參數(shù),或者返回一個(gè)函數(shù)作為結(jié)果的函數(shù)通常就被稱為高階函數(shù)。均屬于高階函數(shù),高階函數(shù)并不神秘,我們?nèi)粘>幊桃矔?huì)用到。參考演算函數(shù)式編程指南入門康托爾哥德?tīng)枅D靈永恒的金色對(duì)角線原文函數(shù)與演算 緣起 造了一個(gè)輪子,根據(jù)GitHub項(xiàng)目地址,生成項(xiàng)目目錄樹(shù),直觀的展現(xiàn)項(xiàng)目結(jié)構(gòu),以便于介紹項(xiàng)目。歡迎Star。 repository-tree 技術(shù)棧: ES6 ...
摘要:函數(shù)聲明靜態(tài)函數(shù)函數(shù)聲明有個(gè)特征就是函數(shù)可以函數(shù)聲明提前函數(shù)表達(dá)式這種方式命名,沒(méi)有函數(shù)聲明提前,這個(gè)方式也是自己比較喜歡用的方式。 函數(shù)聲明(靜態(tài)函數(shù)) 函數(shù)聲明有個(gè)特征就是函數(shù)可以函數(shù)聲明提前 hello(); function hello(){ console.log(hello js); } 函數(shù)表達(dá)式(Function expressions) var hello2...
摘要:函數(shù)和所生成的過(guò)程來(lái)源譯者飛龍協(xié)議函數(shù)是計(jì)算過(guò)程的局部演化模式。在這一章中,我們會(huì)檢測(cè)一些用于簡(jiǎn)單函數(shù)所生成過(guò)程的通用模型。也就是說(shuō),遞歸函數(shù)的執(zhí)行過(guò)程可能需要再次調(diào)用這個(gè)函數(shù)。 3.2 函數(shù)和所生成的過(guò)程 來(lái)源:3.2 Functions and the Processes They Generate 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 函數(shù)是計(jì)算過(guò)程的局部演化...
閱讀 2079·2021-11-19 09:40
閱讀 2032·2021-09-28 09:36
閱讀 2366·2021-09-22 10:02
閱讀 2805·2019-08-30 14:00
閱讀 2017·2019-08-29 15:31
閱讀 2963·2019-08-29 15:11
閱讀 2973·2019-08-29 13:04
閱讀 1146·2019-08-27 10:55