什么是函數(shù)?
函數(shù)是封裝一段代碼段的對象
函數(shù)名其實僅是引用函數(shù)對象的一個普通變量
為什么使用函數(shù)?
代碼重用
何時使用函數(shù)?
只要一項任務被反復使用,就要定義為函數(shù),反復使用函數(shù)
那么,如何進行創(chuàng)建函數(shù)呢?創(chuàng)建函數(shù)有3種方法:
1.聲明:
function 函數(shù)名(參數(shù)列表){
函數(shù)體;
return 返回值;
}
//需不需要返回值,就要看函數(shù)調用者要不要這個返回結果
- 問題:
hoist:聲明提前,打亂了正常的程序順序!
如何解決聲明提前?用第二種解決聲明提前!

ex:聲明提前(hoist)
console.log(a);//undefined
var a=10;
console.log(a);//10
function fun(){
console.log(1);
}
fun();//2
function fun(){
console.log(2)
}
fun();//2
/*為什么會出現(xiàn)兩個輸出結果都是2呢?
因為出現(xiàn)了聲明提前,把1調到程序頂部后又把2調到了頂部,
輸出只輸出最后邊的值。*/
2.直接量:var 函數(shù)名=function (參數(shù)列表){……}
優(yōu)點:不會被聲明提前!
函數(shù)的本質:函數(shù)其實就是一個引用類型的對象,和數(shù)組一樣。不同的是,數(shù)組中存的值,函數(shù)中寸的是代碼。就像冰箱和菜譜一樣的,冰箱存的菜。而菜譜存的是做菜的方法。
- function:創(chuàng)建一個新函數(shù)的意思
- 函數(shù)名其實就是一個引用
ex:聲明提前解決!??!
console.log(a);//undefined
var a=10;
console.log(a);//10
var fun=function fun(){
console.log(1);
}
fun();//1
var fun=function fun(){
console.log(2)
}
fun();//2
3.用new:(了解)
var 函數(shù)名=new Function("參數(shù)變量",…,"函數(shù)體")
var cmp=new Function(a,b,"return a-b") 錯誤的!
var cmp=new Function("a","b","return a-b") 正確!
重載(arguments只在重載的時候使用?。?/h2>
什么是重載:相同函數(shù)名,不同參數(shù)列表的多個函數(shù)。在調用時,根據(jù)傳入?yún)?shù)的不同,自動選擇對應的函數(shù)執(zhí)行。
為什么:減少函數(shù)的個數(shù),減輕調用者的負擔
何時:今后,只要一項任務,根據(jù)不同的參數(shù),有不同實現(xiàn)邏輯時。
問題:JS中默認不支持重載?。。。?!
什么是重載:相同函數(shù)名,不同參數(shù)列表的多個函數(shù)。在調用時,根據(jù)傳入?yún)?shù)的不同,自動選擇對應的函數(shù)執(zhí)行。
為什么:減少函數(shù)的個數(shù),減輕調用者的負擔
何時:今后,只要一項任務,根據(jù)不同的參數(shù),有不同實現(xiàn)邏輯時。
原因:JS中不允許多個同名函數(shù)同時存在!如果存在多個同名函數(shù),只識別最后一個函數(shù)。
解決:用arguments(參數(shù)們)對象
什么是arguments?arguments就是函數(shù)中自動創(chuàng)建的。
自動接收所有傳入函數(shù)的參數(shù)值的類數(shù)組對象(object like array)。
類數(shù)組對象(object like array):長的像數(shù)組一樣的對象。
類數(shù)組對象 vs 數(shù)組對象(鄙視題)
- 相同:都可以下標訪問每個元素。都有類似屬性。但是類數(shù)組對象不能使用數(shù)組的任何API。Arguments在調用函數(shù)時會在函數(shù)函數(shù)內(nèi)部自動創(chuàng)建,
- 類型不同:類數(shù)組對象的父類型是Object 數(shù)組對象的父類型是Array
導致類數(shù)組對象無法使用數(shù)組類型的方法
類數(shù)組對象 to Array:固定套路:
var arr=Array.prototype.slice.apply/call(arguments);
- 相同點:
1、下標
2、.length
3、for 遍歷 - 不同:類型不同!API不通用!
何時?只要函數(shù)的參數(shù)個數(shù)不確定時,都可用arguments接住所有參數(shù)值。
問題:今后還需不需要參數(shù)?
參數(shù)的作用:
1.提醒調用者,如何正確使用函數(shù)!
2.一般自定義的參數(shù)名,都是見名知意,且都非常簡單。
所以函數(shù)首先先用參數(shù)變量來接受參數(shù)值,而不是arguments,只在重載的時候使用arguments。
ex:使用arguments代替重載
function pay(){
//arguments:[ ].length
// 0 1 2
if(arguments.length==0){
console.log("手機支付:掃碼");
}else if(arguments.length==1){
console.log("現(xiàn)金支付");
}else{
console.log("刷卡結賬");
}
}
pay(100,100);//現(xiàn)金支付
匿名函數(shù)
什么是匿名函數(shù):匿名函數(shù)是指在創(chuàng)建函數(shù)時不使用函數(shù)名的函數(shù)。
為什么:節(jié)約內(nèi)存,劃分臨時作用域。
何時:
1.如果一個函數(shù)只使用一次時
2.如果避免使用全局變量,劃分臨時作用域時
- 如何使用2種:
-1.回調(絕大多數(shù)的回調都是使用匿名函數(shù)):將一個函數(shù),交給另一個函數(shù)去調用。
回調函數(shù)(3種)
1、sort比較器
2、str.replace高級替換
3、事件處理函數(shù)
ex:sort比較器
var arr=[1,2,122,2,23,233];
function cmp(a,b){return a-b;}
arr.sort(cmp);
//[1, 2, 2, 23, 122, 233]
- 自調:創(chuàng)建函數(shù)后,立刻調用自己
為什么:避免使用全局變量
何時:今后幾乎所有的JS程序,都應該放在匿名函數(shù)自調中
如何自調:(function(參數(shù)列表){函數(shù)體})();
作用域(scope)
什么是:一個變量的可用范圍——(用途)
作用域其實就是一個存儲變量的對象——(本質)
為什么:避免不同范圍的變量間互相干擾。
包括(2種):
1.全局作用域:不屬于任何函數(shù)的外部的范圍
全局變量:可反復使用且隨處可用
2.函數(shù)作用域:函數(shù)內(nèi)的范圍
其實:活動對象active object(AO)
局部變量:僅函數(shù)內(nèi)可用,不可反復使用!
作用域鏈(scope chain)
由多級作用域,連續(xù)引用形成的鏈式結構
存儲了所有變量
控制變量的使用順序:先局部,后全局。
函數(shù)的生命周期:(4步)
1、開始執(zhí)行程序前
創(chuàng)建執(zhí)行環(huán)境棧(ECS):保存正在調用的函數(shù)記錄
首先先自動調用瀏覽器主程序main()
主程序創(chuàng)建全局作用域對象window

2、定義函數(shù)時
在window中用函數(shù)名創(chuàng)建全局變量
window外創(chuàng)建函數(shù)對象,保存函數(shù)定義
函數(shù)名變量引用函數(shù)對象
函數(shù)對象的scope屬性指回函數(shù)來自的作用域對象

3、調用函數(shù)時
在ECS中壓入當前函數(shù)的調用記錄
為本次函數(shù)調用創(chuàng)建活動對象AO
AO中保存局部變量
讓AO指向函數(shù)的scope屬性指向相同對象window
變量的使用順序:優(yōu)先用AO中的局部變量,AO中沒有才去window找


4、函數(shù)調用后

閉包
什么是閉包:即重用變量,又保護變量不受污染的一種機制
為什么用閉包?
全局變量:優(yōu)點:可以重用!缺點:污染,隨處可用!
局部變量:優(yōu)點:僅函數(shù)內(nèi)可用,且不會污染全局!缺點:不可重用!
何時:只要即重用一個變量,又保護變量不受污染時
閉包形成的原因:外層函數(shù)的作用域對象無法釋放,被內(nèi)層函數(shù)對象引用著
如何使用閉包:3步:
1.用外層函數(shù)包裹要保護的變量和操作變量的函數(shù)
2.外層函數(shù)將內(nèi)層函數(shù)的對象返回外部
3.使用者調用外層函數(shù),獲得內(nèi)層函數(shù)對象
//第一步,用外層函數(shù)包裹受保護的變量和內(nèi)層函數(shù)
function outer(){
var i=1;
//第二步,外層函數(shù)將內(nèi)層函數(shù)返回外部
return function(){
console.log(i++);
}
}
//第三步,使用者調用外層函數(shù)獲得內(nèi)層函數(shù)的對象
var getNum=outer();
getNum();
getNum();
i=1;//無法對函數(shù)內(nèi)的i進行修改,故無效
getNum();
getNum();
//控制臺輸出:1,2,3,4
簡圖: 2步:
- 找受保護的變量,并確定其最終值
- 找使用變量的內(nèi)層函數(shù)對象,只有內(nèi)層函數(shù)才能使用受保護的變量
閉包缺點: 比普通函數(shù)占用更多內(nèi)存空間!
解決: 閉包不再使用,要及時釋放
如何釋放: 將引用內(nèi)層函數(shù)對象的變量賦值為null
ex:閉包例題:自報按鈕序號
<button>click me!</button>
<button>click me!</button>
<button>click me!</button>
<button>click me!</button>
<button>click me!</button>
<script>
var btns=document.getElementsByTagName("button");
for(var i=0;i<btns.length;i++){
btns[i].onclick=(function(){
var index=i+1;
return function(){
alert("我是第"+index+"個");
}
})();
}