闭包与循环中的函数

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对象。   并不是我想要的。所以在定义对象的方法的时候应该避免使用箭头函数。
    //箭头函数一般用在传递参数,或者在函数内部声明函数的时候使用。

猜你喜欢

转载自blog.csdn.net/weixin_42355871/article/details/83716807