函數(shù)聲明和函數(shù)表達(dá)式
- 函數(shù)聲明
function fn() {}
- 必須有函數(shù)名
- 函數(shù)可以在任意地方調(diào)用
- 函數(shù)表達(dá)式
var fn = function fn() {}
-
function
后函數(shù)名可以省略 -
function
后函數(shù)名只能在函數(shù)內(nèi)部使用 - 函數(shù)表達(dá)式只能在聲明之后才能調(diào)用
-
作用域和聲明提升
-
作用域
- 變量作用域
- 全局變量擁有全局作用域面睛,局部變量只在函數(shù)體內(nèi)有定義
- 函數(shù)體內(nèi)喜德,局部變量優(yōu)先級高于同名的全局變量
- 函數(shù)作用域
- 與
塊級作用域
概念類似的找岖,JavaScript 使用函數(shù)作用域(function scope
)剥槐,即在函數(shù)體內(nèi)聲明的所有變量在函數(shù)體內(nèi)可以使用及復(fù)用
- 與
- 變量作用域
-
聲明提升
在代碼開始執(zhí)行之前砰蠢,解析器會(huì)在初始化進(jìn)程中創(chuàng)建全局變量對象
VO(variable object)
古程,VO
中包含全局對象原有屬性户盯,全局定義的變量和函數(shù)-
VO
的變化與上下文代碼的兩個(gè)執(zhí)行階段有關(guān)- 變量初始化询枚,進(jìn)入執(zhí)行上下文
- 執(zhí)行代碼
- 在變量初始化階段违帆,
VO
會(huì)被以下屬性按優(yōu)先級順序填充- 函數(shù)參數(shù)(未傳入實(shí)參時(shí),初始值為
undefined
) - 函數(shù)聲明(存在相同名稱的屬性時(shí)金蜀,會(huì)完全替換該屬性)
- 變量聲明(初始值為
undefined
刷后,存在相同名稱的屬性時(shí)會(huì)忽略該聲明)
- 函數(shù)參數(shù)(未傳入實(shí)參時(shí),初始值為
- 在執(zhí)行代碼階段,依據(jù)以上流程渊抄,可得知 JavaScript
聲明提升(declaration hoisting)
特性的結(jié)果惠险,即:- 將 JavaScript 函數(shù)聲明的所有變量添加到執(zhí)行環(huán)境中,并將它們按優(yōu)先級順序放到源代碼樹的頂部抒线,故函數(shù)聲明提升在變量聲明提升之前
var haha = function() { console.log('賦值給變量haha') } function haha() { console.log('具名函數(shù)haha') } haha(); //賦值給變量haha
-
arguments
對象
-
arguments
對象是所有函數(shù)中都可用的局部變量班巩,此對象包含傳遞給函數(shù)的每個(gè)參數(shù)的條目,示例:arguments[0] //對應(yīng)第一個(gè)參數(shù)的條目 arguments[1] //類推嘶炭,第二個(gè) arguments[2] arguments[1] = 'new Value'; //參數(shù)可被設(shè)置
-
arguments
對象類似Array
抱慌,但不是Array
,除了length
屬性來確定傳遞參數(shù)個(gè)數(shù)外沒有任何Array
屬性
函數(shù)的重載
- Java 和 JavaScript 的對比
- Java 中眨猎,通過方法簽名來唯一確定一個(gè)方法抑进。方法簽名的要素包括:方法名、參數(shù)類型睡陪、參數(shù)順序和參數(shù)個(gè)數(shù)寺渗。若兩個(gè)方法名稱相同匿情,但其他要素不同,編譯器便將其視為同名的不同方法信殊,從而導(dǎo)致了
重載
現(xiàn)象 - JavaScript 中炬称,函數(shù)沒有簽名,其參數(shù)由包含零或多個(gè)值的數(shù)組來表示涡拘,完全靠函數(shù)名稱唯一確定玲躯。當(dāng)存在相同名稱的函數(shù)時(shí),則后者會(huì)覆蓋前者鳄乏,因而不存在
重載
- Java 中眨猎,通過方法簽名來唯一確定一個(gè)方法抑进。方法簽名的要素包括:方法名、參數(shù)類型睡陪、參數(shù)順序和參數(shù)個(gè)數(shù)寺渗。若兩個(gè)方法名稱相同匿情,但其他要素不同,編譯器便將其視為同名的不同方法信殊,從而導(dǎo)致了
- JavaScript 模仿函數(shù)的
重載
//通過檢查傳入函數(shù)中參數(shù)的數(shù)量跷车,間接達(dá)到重載的目的 function add(num1, num2) { if(arguments.length == 1) { console.log(arguments[0] + "input 2nd parameter") } if(arguments.length == 2) { console.log(arguments[0] + arguments[1]) } }
立即執(zhí)行函數(shù)表達(dá)式 IIFE
IIFE
即聲明一個(gè)匿名函數(shù)并即時(shí)調(diào)用
- 兩種模式
- 當(dāng)圓括號包裹函數(shù)時(shí),它會(huì)默認(rèn)將函數(shù)作為表達(dá)式去解析橱野,而不是函數(shù)聲明
(function() { /* code */}());
- 當(dāng)圓括號出現(xiàn)在匿名函數(shù)的末尾想要調(diào)用函數(shù)時(shí)朽缴,它會(huì)默認(rèn)將函數(shù)當(dāng)成是函數(shù)聲明
(function() { /* code */})();
- 當(dāng)圓括號包裹函數(shù)時(shí),它會(huì)默認(rèn)將函數(shù)作為表達(dá)式去解析橱野,而不是函數(shù)聲明
- 用途
- 創(chuàng)建一個(gè)獨(dú)立的作用域,避免全局污染
// 這是一個(gè)自執(zhí)行函數(shù)水援,函數(shù)內(nèi)部執(zhí)行的是自己不铆,遞歸調(diào)用
function foo() { foo(); }
// 這是一個(gè)自執(zhí)行匿名函數(shù),因?yàn)樗鼪]有函數(shù)名
// 所以如果要遞歸調(diào)用自己的話必須用arguments.callee
var foo = function() { arguments.callee(); };
// 這可能也算是個(gè)自執(zhí)行匿名函數(shù)裹唆,但僅僅是foo標(biāo)志引用它自身
// 如果你將foo改變成其它的誓斥,你將得到一個(gè)used-to-self-execute匿名函數(shù)
var foo = function() { foo(); };
// 有些人叫它自執(zhí)行匿名函數(shù),盡管它沒有執(zhí)行自己许帐,只是立即執(zhí)行而已
(function(){ /* code */ }());
// 給函數(shù)表達(dá)式添加了標(biāo)志名稱劳坑,可以方便debug
// 但是一旦添加了標(biāo)志名稱,這個(gè)函數(shù)就不再是匿名的了
(function foo(){ /* code */ }());
// 立即執(zhí)行函數(shù)也可以自執(zhí)行成畦,不過不常用罷了
(function(){ arguments.callee(); }());
(function foo(){ foo(); }());
遞歸求n!
function fn(i) {
if(i < 2) {
return 1
}else {
return i*fn(i-1)
}
}
//簡寫
function fn(i) {
return i<2?1:i*fn(i-1)
}
refer to 變量對象 | cnblogs距芬,立即執(zhí)行函數(shù)表達(dá)式(IIFE) | segmentfault,立即執(zhí)行函數(shù) | 每日一題