1、背景介紹
定義函數(shù)的方法主要有三種:
1:函數(shù)聲明(Function Declaration)
2:函數(shù)表達(dá)式Function Expression)
3:new Function構(gòu)造函數(shù)
其中,經(jīng)常使用的是函數(shù)聲明和函數(shù)表達(dá)式的函數(shù)定義方法,這兩種方法有著很微妙的區(qū)別和聯(lián)系,
而且這兩種方法的使用也容易混淆,所以我們來講一下兩者有哪些不同之處
2:知識剖析
函數(shù)聲明的典型格式:
function functionName(arg1, arg2, ...){}
函數(shù)表達(dá)式
函數(shù)表達(dá)式的典型格式:
var ?variable=function(arg1, arg2, ...){}
3、常見問題
兩者具體有哪些區(qū)別呢
4:解決方案
一、Javascript引擎在解析javascript代碼時(shí)會‘函數(shù)聲明提升'(Function declaration Hoisting)
當(dāng)前執(zhí)行環(huán)境(作用域)上的函數(shù)聲明,而函數(shù)表達(dá)式必須等到Javascirtp引擎執(zhí)行到它所在行時(shí),
才會從上而下一行一行地解析函數(shù)表達(dá)式
,二、函數(shù)表達(dá)式后面可以加括號立即調(diào)用該函數(shù),函數(shù)聲明不可以,只能以fn()形式調(diào)用 。
以下是兩者差別的兩個(gè)例子。
fn1();//不會報(bào)錯(cuò),因?yàn)?提升了"函數(shù)聲明,函數(shù)調(diào)用可在函數(shù)聲明之前
functionfn1(){
console.log("這里是函數(shù)聲明");
}
fn2();//會報(bào)錯(cuò),變量fn2還未保存對函數(shù)的引用,函數(shù)調(diào)用必須在函數(shù)表達(dá)式之后
varfn2=function(){
console.log("這里是函數(shù)表達(dá)式");
}
關(guān)于立即執(zhí)行函數(shù)的討論
//情況1
//結(jié)果會被輸出
varfn=function(){
console.log("函數(shù)表達(dá)式賦值給一個(gè)變量");
}();
//情況2
//結(jié)果不會被輸出,JavaScript引擎只解析函數(shù)聲明,忽略后面的括號,函數(shù)聲明不會被調(diào)用
functionfn(){
console.log("函數(shù)聲明");
}();
//情況3
//語法錯(cuò)誤,匿名函數(shù)屬于函數(shù)表達(dá)式,未執(zhí)行賦值操作,不能被調(diào)用
function(){
console.log("函數(shù)表達(dá)式");
}();
5:編碼實(shí)戰(zhàn)
同上
6:深度思考
使用兩種方式創(chuàng)建函數(shù)時(shí)都發(fā)生了什么
函數(shù)聲明解析過程如下:
1. 創(chuàng)建一個(gè)new Function對象,F(xiàn)ormalParameterList指定參數(shù),F(xiàn)unctionBody指定函數(shù)體。
將當(dāng)前正在運(yùn)行環(huán)境中作用域鏈作為它的作用域。
2. 為當(dāng)前變量對象創(chuàng)建一個(gè)名為Identifier的屬性,值為Result(1)。
具名函數(shù)表達(dá)式的解析過程如下:
1. 創(chuàng)建一個(gè)new Object對象
2. 將Result(1)添加到作用域鏈的頂端
3. 創(chuàng)建一個(gè)new Function對象,F(xiàn)ormalParameterList指定參數(shù),F(xiàn)unctionBody指定函數(shù)體。將當(dāng)前正在運(yùn)行的執(zhí)行環(huán)境中作用域鏈作為它的作用域。
4. 為Result(1)創(chuàng)建一個(gè)名為Identifier 的屬性,其值為為Result(3),只讀,不可刪除
5. 從作用域鏈中移除Result(1)
6. 返回Result(3)