欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript匿名函数和闭包

程序员文章站 2022-04-05 10:37:31
...

1,把匿名函数赋值给变量

var test = function() {
    return 'guoyu';
};
alert(test);//test是个函数
alert(test());
  • 1
  • 2
  • 3
  • 4
  • 5

2,把匿名函数自我执行的返回值赋值给变量

var test = (function() {
    return 'GY';
})();
alert(test);//弹出  GY
  • 1
  • 2
  • 3
  • 4

3,自我执行,第一个圆括号放匿名函数,第二个括号执行并传参

(function(a, b) {
    alert(a+b);
})(2,5);//直接弹出7
  • 1
  • 2
  • 3

4,自我执匿名函数的传参

alert((function() {
    return 'guoyu';
})());
  • 1
  • 2
  • 3

5,函数里面放一个匿名函数

function test() {
    return function() {
        return 'guoyu';
    };
}
alert(test());//执行test(),结果是一个函数体
alert(test()());//弹出guoyu

var t = test();
alert(t());//弹出guoyu
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

闭包

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

1,通过闭包可以返回局部变量

function test() {
    var age = 28;
    return function() {
        return age;
    };
}
alert(test()());//直接弹出 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2,使用闭包有个优点,同时也是缺点:局部变量驻留内存中,可以避免使用全局变量(全局变量污染导致应用程序的不可预知性,每个模块都可以调用必将引来灾难,推荐使用私有的,封装的局部变量)

使用全局变量进行累加
var age = 20;
function test() {
    age++;
    return age;
}
alert(test());//21
alert(test());//22
如果你把var age = 20;放进test()函数内,那么每次执行都会重新初始化为20,每次弹出的都是21,无论执行多少次!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3,使用匿名函数实现局部变量驻留内存中从而累加

function test() {
    var age = 20;
    return function() {
        age++;
        return age;
    }
}
var t = test();
alert(t());//21
alert(t());//22
alert(t());//23
alert(t());//24
/*如果每次都初始化age = 20;那么每次返回都是21,不能实现累加,因此要避免初始化那一句,只要调用第一个return 语句即可,每次只调用t()即可*/
t = null;//解除引用,等待垃圾回收
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

循环里的匿名函数的取值问题

function test() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = function() {
            return i;
        };
    }

    //循环执行完毕,i最终是4++,就是5
    return arr;
}

/*
    alert(test());
    打印出5个并列的“function() {return i;}”,
    因为arr数组的每个元素都是一个匿名函数,每个匿名函数都是返回"i",
    并不是返回123....,因为这个匿名函数是死的,没有执行(自执行)
*/
alert(test()[0]);//弹出“function() {return i;}”

var t = test();

for (var i = 0; i < 5; i++) {
    //alert(t[i]);//数组里面都是一个没有自执行的匿名函数


    //现在让数组里的每个死函数执行起来,但是全都是弹出‘5’
    //因为执行test()里的循环后,i已经为5了,但每个数组里面都存的是个死函数,返回一个死i
    alert(t[i]());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

如何解决上述的问题呢?

修改1

function test() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = i;//这里不用匿名函数,直接给个i,
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    alert(t[i]);//依次弹出0,1,2,3,4
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

修改2,通过自我即时执行匿名函数:

//将匿名函数里面的变量驻留到内存感觉像全局变量
function test() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = (function(num) {
            return num;
        })(i);
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    alert(t[i]);//依次弹出0,1,2,3,4
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

修改3:

function test() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = (function(num) {
            //return num;
            return function() {//这么写就是闭包了,闭包将变量驻留在内存,和前例中累加一个道理
                return num;
            };
        })(i);
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    //alert(t[i]);这里返回的是5个依次“function() {return num;}”
    alert(t[i]());//依次打印出0,1,2,3,4
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

闭包中的this

var test = {
    getThis: function() {
        return this;
    }
};

alert(test.getThis());//[object Object]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

再看看闭包中:

var test = {
    getThis: function() {
        return function() {//这么写就是闭包了
            return this;
        };
    }
};

alert(test.getThis()());//[object Window]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结论:this 对象在运行时基于函数的执行环境绑定的,如果this在全局范围就是widow,如果在对象内部就指向这个对象。而闭包在运行时指向window的,因为闭包不属于这个对象的属性或方法,再看下面

var user = 'The Window';
var box = {
    user:'The Box',
    getUser: function() {
        //return this.user;
        return function() {//这么写就是闭包了
            return this.user;
        };
    }
};

alert(box.getUser()());//The Window
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

那么有的同学想问了,怎么才能让它弹出 The box呢?
方法有两个:对象冒充,变量保存_this

var user = 'The Window';
var box = {
    user:'The Box',
    getUser: function() {//这个地方要冒充一下
        return function() {
            return this.user;
        };
    }
};

alert(box.getUser().call(box));//The Box
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
var user = 'The Window';
var box = {
    user:'The Box',
    getUser: function() {
        var _this = this;//保存到临时变量
        return function() {
            return _this.user;
        };
    }
};

alert(box.getUser()());//The Box
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

模仿块级作用域,for ,if 等块级里的东西封装起来,变量私有化,可以保护数据,防止泄露,js没有私有作用域这个概念

function test() {
    for(var i = 0; i < 5; i++) {//块级作用域,可惜JS没这个东西

    }
    var i;//重新声明也不影响
    alert(i);//即使超出for块级,依旧打印出5,说明js没有块级作用域这个概念
}
test();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

开始使用块级作用域,也就是出了if , for等块,里面的i就不再起效,方法就是包含自我执行的匿名函数,就可以实现私有作用域

function test() {
    (function() {
        for (var i = 0; i < 5; i++) {//包含自我执行的匿名函数,就可以实现私有作用域
            alert(i);
        }
    })();

    alert(i);
    //这里i就不认识了,相当于没定义i,i被销毁了,后面继续定义i和上面的i没任何关系,防止污染
}
test();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
(function() {
    var age = 20;
    alert(age);
})();
alert(age);//报错,undefined
//这样可以全局变量私有化,防止污染
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

私有变量(外部不可访问)

function test() {
    var age = 20; //私有变量
}
  • 1
  • 2
  • 3

function Test() {
    this.age = 20;//属性:公有的,外部可访问
    this.run = function() {//方法:公有的
        return 'is running...';
    };
}


var t = new Test();
alert(t.age);
alert(t.run());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
function Test() {
    var age = 20;  //私有变量
    function run() {//私有函数
        return ' is running...';
    }

    this.publicGo = function() { //对外可见的公共接口,特权方法
        return age + run();
    };
}

var t = new Test();
alert(t.publicGo());
//20 is running...私有变量,私有函数,通过公共接口被访问
//把一些细节封装起来,通过一些接口去访问
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
            </div>