1. 程式人生 > >閉包與迴圈中的函式

閉包與迴圈中的函式

1.es5中的函式迴圈遍歷
由於在es5中沒有塊級作用域,會導致一些問題

//迴圈中的函式
    var func = []; //這是個陣列
    for(var i=0;i<10;i++){
        console.log(i);//列印了0-9,這個時候i=10;,不小於10,迴圈遍歷結束
        func.push(function () {
            console.log(i);
            console.log(1)
        });//把數字放到陣列當中

    }
     console.log('迴圈遍歷完',i);// 迴圈遍歷完,這個時候是10
func.forEach(function (func) { // console.log(2); // func(); // console.log(func); //func代表的是function () {console.log(i)} });

2.解決辦法是需要用到函式自執行的特性

var funcs = [];
    //按程式從上至下的執行,先執行for迴圈,得到i等於10,
    //然後foreach進行迴圈遍歷,執行函式呼叫,列印i的值
    //所以列印了10個10
    for(var i=0;i<10;i++){
        console.
log('迴圈遍歷列印',i); //迴圈遍歷列印 funcs.push(function (value) { console.log('函式呼叫前:',value); //把值給返回回來 return function () { console.log('函式自呼叫後',value); } }(i)) //把i的值傳參給value } funcs.forEach(function (func) { console.
log(4); func() });

3.如果使用es6語法進行宣告變數,就可以避免出現這個問題
//如果用let宣告變數,則可以避免前面的問題 for of for in
//let 宣告使得每次迭代都會建立一個變數 i,
// 所以迴圈內部建立的函式會獲得各自的變數 i 的拷貝。
//每份拷貝都會在每次迭代的開始被建立並被賦值。

 var funcss = [];
    for(let i=0;i<10;i++){
        funcss.push(function () {
            console.log('let宣告變數',i); //0-9
        });

    }
    funcss.forEach(function (func) {
        func()

    })

三、函式的新增特性
//預設引數對arguments物件的影響
//在es5,arguments總是能反映命名引數的變化

//預設引數對arguments物件的影響
    //在es5,arguments總是能反映命名引數的變化
    function foo(a,b) {
        console.log(arguments[0] === a);//true
        console.log(arguments[1] === b);//true
        a =10;
        b = 20;
        console.log(arguments[0] === a);//true
        console.log(arguments[1] === b);//true

    }
    foo(1,32);
    function foo(a, b) {
        //嚴格模式
        "use strict"
        console.log(arguments[0] === a); //true
        console.log(arguments[1] === b); //true
        a = 10;
        b = 20;
        console.log(arguments[0] === a); //false。  修改a的值不會影響到arguments[0]的值
        console.log(arguments[1] === b); //false
    }
    foo(1, 2);
    //用了es6語法特性
    function foo(a, b = 30) {
        console.log(arguments[0] === a); //true
        console.log(arguments[1] === b); //true
        a = 10;
        b = 20;
        console.log(arguments[0]  === a); //false。  由於b使用了預設值。雖然a沒有使用預設值,但是仍然表現的和嚴格模式一樣。
        console.log(arguments[1] === b); //false。  b使用了預設值,所以表現的和嚴格模式一樣。
    }
    foo(1, 2);

    //預設引數表示式

        function getValue() {
            return 5;
        }

    function add(first, second = getValue()) { //表示使用getValue這個函式的返回值作為second的預設值。
        return first + second;
    }

    console.log(add(1, 1));     // 2.  呼叫add函式的時候,傳入了第二個引數,則以傳入的引數為準。
    console.log(add(1));  //getValue為5      // 6。 呼叫add函式的時候,沒有傳入第二個引數,則會呼叫getValue函式。


    //未命名引數問題
    function hu(a,...b) {
        console.log(a);
        console.log(b);

    }
    hu(1,2,3,4,5);

    //函式中的擴充套件運算子
    let values = [25,30,40,50,70];
    console.log(Math.max(...values));//70 //相當於拆解陣列,使用擴充套件運算子
    console.log(Math.max(...values,200));//200

四、箭頭函式

 //箭頭函式
    // (形參列表)=>{
    //     //函式體
    // }
    //箭頭函式可以賦值給變數,也可以像匿名函式一樣直接作為引數傳遞
    var sum = (num1,num2)=>{
        return num2+num1;
    }
    console.log(sum(3,5));
    var add = (num1,num2)=>num1+num2;
    console.log(add(1,2))

    //使用箭頭函式實現函式自執行
    var person = (name=>{
        return {
            name:name,
            age:30,
        }
    })('huzhenyu');
    console.log(person);//使用箭頭函式返回一個物件,age預設,name是進行傳參

    let page = {
        id:'132323',
        init:function () {
            console.log('init',this);
            // 在此處this的和init函式內的this相同。
            document.addEventListener('click',
                (event)=>{
                    this.doSomething(event.type)
                    console.log('event',this)

                }
            ,false);


        },
        doSomething:function (type) {
            console.log('handle'+type+'for'+this.id);

        }
    };
    page.init();

    //箭頭函式無this繫結
    var p = {
        foo:()=>console.log(this)   //此處this為window
    }
    p.foo();  //輸出為 window物件。   並不是我想要的。所以在定義物件的方法的時候應該避免使用箭頭函式。
    //箭頭函式一般用在傳遞引數,或者在函式內部宣告函式的時候使用。