Function

什么是函數(shù)?

函數(shù)是封裝一段代碼段的對象
函數(shù)名其實僅是引用函數(shù)對象的一個普通變量

為什么使用函數(shù)?

代碼重用

何時使用函數(shù)?

只要一項任務被反復使用,就要定義為函數(shù),反復使用函數(shù)

那么,如何進行創(chuàng)建函數(shù)呢?創(chuàng)建函數(shù)有3種方法:

1.聲明:
function 函數(shù)名(參數(shù)列表){
    函數(shù)體;
    return 返回值;
}
//需不需要返回值,就要看函數(shù)調用者要不要這個返回結果
  • 問題:

hoist:聲明提前,打亂了正常的程序順序!
如何解決聲明提前?用第二種解決聲明提前!

Paste_Image.png
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中默認不支持重載?。。。?!

原因: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

1_程序開始執(zhí)行前.png

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

2_定義函數(shù)時.png

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

3_調用函數(shù)時1.png
4_調用函數(shù)時2.png

4、函數(shù)調用后

5_調用函數(shù)后.png

閉包

什么是閉包:即重用變量,又保護變量不受污染的一種機制

為什么用閉包?
全局變量:優(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步:

  1. 找受保護的變量,并確定其最終值
  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+"個");
        }
    })();
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容