函數(shù)的聲明
JavaScript中函數(shù)使用 function
關(guān)鍵字聲明
匿名函數(shù)的聲明
匿名函數(shù)聲明語法:
function (函數(shù)的參數(shù)){ 函數(shù)塊 }
只聲明匿名函數(shù)的代碼是不正確的
function a(){}
匿名函數(shù)經(jīng)常被用作回調(diào)函數(shù)盟迟。
緊接著匿名函數(shù)聲明后"
}
"的調(diào)用是不正確的,例如下面的代碼
function a(){}()
函數(shù)聲明其實(shí)是語句潦闲,但是當(dāng)函數(shù)聲明在表達(dá)式位置(右值)時队萤,函數(shù)聲明便可成為表達(dá)式(在非匿名函數(shù)命名處有例子)。
可以使用一些黑魔法("()
"矫钓、",
"要尔、"!
")把函數(shù)聲明轉(zhuǎn)換為表達(dá)式舍杜,其返回值是被聲明的函數(shù)。
以下的代碼都是正確的> (function () { ... console.log('Hello,world'); ...})() Hello,world < undefined //匿名函數(shù)的返回值(如果沒有返回值則為undefined)
>(function () { ... console.log('Hello,world'); ...}()) Hello,world < undefined //匿名函數(shù)的返回值(如果沒有返回值則為undefined)
> 1, function () { ... console.log('Hello,world'); ...})() Hello,world < undefined
> !function () { ... console.log('Hello,world'); ...}) Hello,world < undefined
原因猜測(以下純屬瞎猜赵辕,有錯隨意懟我):
要解釋這個問題既绩,首先需要介紹JavaScript某個特性——Automatic Semicolon Insertion(ASI,自動分號插入機(jī)制)(ES6規(guī)范)
ASI
為了書寫方便还惠,在某些情況下作為語句結(jié)束的標(biāo)志——"
;
”可以省略不寫饲握,而在解釋時被自動添加(其實(shí)也不添加";
",只是解釋器 "正確" 理解了在此處就是語句的結(jié)束)蚕键。
解釋器也不是隨意插入";
"的救欧,但是是基于以下這兩點(diǎn)的:
1.以換行為基礎(chǔ)。
2.解析器會盡量將新行并入當(dāng)前行锣光,當(dāng)且僅當(dāng)符合ASI規(guī)則
且不符合No ASI規(guī)則
時才會將新行視為獨(dú)立的語句笆怠。ASI規(guī)則
1.新行并入當(dāng)前行將構(gòu)成非法語句,自動插入分號誊爹。
2.在continue,return,break,throw后自動插入分號蹬刷。
3.++、--后綴表達(dá)式作為新行的開始频丘,在行首自動插入分號办成。No ASI規(guī)則
1.新行以"
(
"開始
1.新行以"[
"開始
1.新行以"/
"開始
1.新行以"+
"、"-
"搂漠、"%
"迂卢、"*
"開始
1.新行以",
"或".
"開始匿名函數(shù)聲明本來是表達(dá)式,但是由于
ASI
桐汤,自動給"}
"末尾加了個";
"(雖然好像并不符合ASI規(guī)則
), 就被解釋為語句而克。
根據(jù)No ASI規(guī)則
就可以反制因?yàn)?ASI
造成"}
"末尾加了個";
"的情況。
ASI在后面出場率比較高惊科,因?yàn)檫@個特性(duliu)可以背很多鍋(沒錯,我是寫分號黨的人)亮钦。
(官方正經(jīng)的解釋在這兒)
非匿名函數(shù)的聲明
非匿名函數(shù)聲明語法:
function 函數(shù)名 (函數(shù)的參數(shù)) { 函數(shù)塊 }
非匿名函數(shù)聲明后不可以緊接著 "}
"進(jìn)行函數(shù)調(diào)用馆截。
下面的代碼是不正確的
function a(){
console.log("Hello,world")
}()
下面的例子雖然沒有語法錯誤,但是并沒有調(diào)用 a
函數(shù)蜂莉,因?yàn)?(1)
沒有解釋為函數(shù)調(diào)用蜡娶,而被解釋為將 1
轉(zhuǎn)換為表達(dá)式
function a(a){
console.log("Hello,world")
}(1)
函數(shù)的命名
函數(shù)命名規(guī)則遵從變量和常量命名規(guī)則(小寫駝峰法)。
但函數(shù)和變量不能取相同的名稱映穗,否則同名變量會被覆蓋窖张。
其實(shí)函數(shù)聲明是特殊的變量聲明,任何函數(shù)聲明都可以轉(zhuǎn)換為將一個匿名函數(shù)賦值給函數(shù)名同名變量蚁滋。
例如以下代碼等價:
function a(){}
var a = function(){}
此時匿名函數(shù)聲明出現(xiàn)在了表達(dá)式位置宿接,但是很奇怪的是第二種聲明語法并沒有返回值赘淮。
所有的函數(shù)聲明都由var
關(guān)鍵字聲明,因此所有函數(shù)聲明都會被JavaScript提前睦霎。
且若有同名變量則會因重復(fù)聲明而被覆蓋梢卸。
同時也說明兩個函數(shù)不能有相同的函數(shù)名(函數(shù)其實(shí)就是特殊的變量),
也就是說JavaScript不支持重載副女,JavaScript只通過函數(shù)名來判斷兩個函數(shù)是否是同一個函數(shù)而不檢查函數(shù)簽名蛤高。
函數(shù)的參數(shù)
函數(shù)的參數(shù)可以為0個或多個。
若為0個則留空即可碑幅。例如 function a(){}
就聲明了一個沒有參數(shù)的函數(shù)戴陡。
若為1個以上則不同參數(shù)之間要用 ,
分割。
例如以下代碼聲明了帶有多個參數(shù)的函數(shù)
function a(b, c, d, e, f){}
與強(qiáng)類型語言不同沟涨,弱類型語言在聲明函數(shù)時不需要指明函數(shù)參數(shù)類型
這是弱類型語言與強(qiáng)類型語言很不同的一點(diǎn)恤批。
函數(shù)的調(diào)用
1.函數(shù)/方法調(diào)用模式:
函數(shù)名(傳遞的參數(shù))
2.構(gòu)造器調(diào)用模式
new 函數(shù)名(傳遞的參數(shù))
傳遞的參數(shù)
語法與函數(shù)的參數(shù)
語法相同,在此不再贅述拷窜。
當(dāng)傳遞參數(shù)的個數(shù)與聲明不匹配時开皿,按照以下方式處理:
1.傳遞參數(shù)個數(shù)大于聲明參數(shù)個數(shù): 忽略多余傳遞參數(shù)(但會去計算)。
例如:
> function a(a){
... console.log(a);
...}
< undefined
> var b = 1;
< 1 //賦值語句的返回值
> a(b, b++, ++b)
1 //b在自增前的值
< undefined
> b
< 3 //b經(jīng)過兩次自增后的值
2.傳遞參數(shù)個數(shù)小于聲明參數(shù)個數(shù): 剩余聲明參數(shù)的值全部為 undefined
篮昧。
arguments
變量除了在函數(shù)中聲明的形參外你會得到一個"免費(fèi)配送的"
arguments
變量(即使函數(shù)沒有形參但arguments
依然存在)赋荆。
你可以通過arguments.length
得到傳遞參數(shù)的個數(shù)。你也可以通過arguments[i]
來獲取每一個參數(shù)懊昨。
arguments
看起來像一個數(shù)組窄潭,其實(shí)不是一個數(shù)組,它是一個屬性名稱為從 0 到arguments.length - 1
的對象(這個特殊的對象我們將在對象詳細(xì)研究)酵颁。
以下代碼便可說明問題:> function a(){ ...console.log(arguments); ...} < undefined > a(1, 2, 3, 4, 5, 6, 7) { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6, '6': 7 } < undefined
arguments
不是關(guān)鍵字嫉你,因此它可以被同名變量、常量或函數(shù)覆蓋躏惋,
甚至你可以給它賦值(但是arguments
不會改變幽污,這個現(xiàn)象會在對象解釋)。
如果函數(shù)確實(shí)有形參且你改變了形參的值簿姨,相應(yīng)的變化會追蹤到arguments
中距误。
但在嚴(yán)格模式
下,"arguments" 不能作為變量扁位、常量或函數(shù)的名稱准潭,且形參的變化不會追蹤到arguments
中。
arguments
的MDN文檔在這里域仇。
函數(shù)中的this
函數(shù)中可以使用 this
關(guān)鍵字獲得特定的對象刑然,根據(jù)函數(shù)調(diào)用方式的不同,this
指向的對象也不盡相同暇务。
方法調(diào)用模式:
當(dāng)一個函數(shù)被保存為對象的一個屬性時泼掠,我們稱它為一個方法怔软。
當(dāng)一個方法被調(diào)用時,this
被綁定到該對象(這種調(diào)用模式將會在對象詳細(xì)介紹)武鲁。函數(shù)調(diào)用模式:
當(dāng)一個函數(shù)并非一個對象的屬性時爽雄,那么它就是被當(dāng)作一個函數(shù)來調(diào)用的。以此模式調(diào)用函數(shù)時沐鼠,this
被綁定到全局對象挚瘟。
在嚴(yán)格模式調(diào)用時,this
如果是全局變量則會被賦值為null
饲梭。
改變函數(shù)中
this
所指對象的方法這里的方法指的是
Function
原型的方法乘盖,函數(shù)其實(shí)也是特殊的對象。
apply
方法:
apply
方法的函數(shù)簽名為apply(thisArg, [argArray])
其中thisArg
是在函數(shù)內(nèi)代替this
的對象憔涉,argArray
是給函數(shù)傳遞的參數(shù)订框。
apply
方法的返回值為函數(shù)調(diào)用后的返回值。
apply
的MDN文檔在這里兜叨。
call
方法:
call
方法的函數(shù)簽名為call(thisArg[, arg1[, arg2[, ...]]])
其中thisArg
是在函數(shù)內(nèi)代替this
的對象穿扳,arg1
、arg2
国旷、...是給函數(shù)傳遞的參數(shù)矛物。
call
方法的返回值為函數(shù)調(diào)用后的返回值。
call
的MDN文檔在這里跪但。
bind
方法:
bind
方法的函數(shù)簽名為bind(thisArg[, arg1[, arg2[, ...]]])
其中thisArg
是在函數(shù)內(nèi)代替this
的對象履羞,arg1
、arg2
屡久、...是給函數(shù)傳遞的參數(shù)忆首。
bind
方法的返回值是一個新的函數(shù),在函數(shù)體內(nèi)this
指向thisArg
對象被环。
bind
的MDN文檔在這里糙及。
從函數(shù)中返回
使用 return
關(guān)鍵字就可以返回函數(shù)的值。
語法: return 返回值
注意: JavaScript中函數(shù)只能擁有一個返回值筛欢,函數(shù)一經(jīng)返回就立即跳出函數(shù)體浸锨。