javascript 闭包详解

一、什么是匿名函数

创建一个函数并将它赋值给变量functionName,这种情况下创建的函数,即匿名函数。(函数表达式就是匿名函数)

二、闭包

1.什么是闭包?

闭包就是能够读取其他函数内部变量的函数。

只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

我们只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

function f1 () {
    var num = 1;
    function f2() {
        console.log(num)
    }
    return f2;
}
var result = f1();
console.log(result());  //1

2、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

function f1 () {
    var num = 1;
    function f2() {
        console.log(++num)
    }
    return f2;
}
var result = f1();
console.log(result());  //2
console.log(result());  //3

原因就在于f1是f2的父函数,而f2的作用域绑上了f1函数的活动对象和全局变量对象(全家对象只有在网页关闭时才会销毁),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

3.使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

 var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
                return this.name;   
     };   
    }
};
alert(object.getNameFunc()());  //The Window  匿名函数的执行环境具有全局性,因此其this对象通常指向window。

4.闭包的应用场景

1.使用闭包代替全局变量

//全局变量,test1是全局变量
var test1=111;
function outer(){
    console.log(test1);
}
outer(); //111
console.log(test1); //111

//闭包,test2是局部变量,这是闭包的目的
//我们经常在小范围使用全局变量,这个时候就可以使用闭包来代替。
(function(){
    var test2=222;
    function test(){
        console.log("测试闭包:"+test2);
    }
    test(); //测试闭包:222
}
)();
console.log(test2); //未定义,这里就访问不到test2 

再如:
(function(){
    var now = new Date();
    if(now.getMonth() == 0 && now.getDate() == 1){
        console.log("Happy new year!")
    }
})();

2.函数外或在其他函数中访问某一函数内部的参数

function test () {
    var num = 1;
    function other() {
        console.log(++num)
    }
    return other;
}
var result = test();
console.log(result());  //2
console.log(result());  //3

3.利用闭包模仿块级作用域

(function(){
    for(var i =0;i<5;i++){
        console.log(i)
    }
    console.log(i); //5  //本身只是到4,但这个地方还是访问到了,所有输出了5
})();
console.log(i); //undefined  //利用闭包后,便形成了块级作用域,让外面访问不到了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老九学堂

十七个C语言新手编程时常犯的错误及解决方式

编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。

1554
来自专栏用户2442861的专栏

json格式

  1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(reco...

2122
来自专栏飞雪无情的博客

Go语言参数传递是传值还是传引用

其实对于传值和传引用,是一个比较古老的话题,做研发的都有这个概念,但是可能不是非常清楚。对于我们做Go语言开发的来说,也想知道到底是什么传递。

1913
来自专栏Pythonista

封装与扩展性

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码...

923
来自专栏绿巨人专栏

[Java] 设计模式: Code Shape - 管理你的代码结构

912
来自专栏Java3y

Object对象你真理解了吗?

2739
来自专栏康怀帅的专栏

Redis string 类型

可以是字符串、整数或浮点,统称为元素。对字符串操作,对整数类型加减。 追加 set key value append key 1 get key 赋值 se...

2986
来自专栏个人分享

工程开发实用类与方法总结(未完)

1 .checkArgument(boolean) :   功能描述:检查boolean是否为真。 用作方法中检查参数   失败时抛出的异常类型: Illeg...

1073
来自专栏绿巨人专栏

[Java] 设计模式: Code Shape - 管理你的代码结构

4236
来自专栏C/C++基础

C++ struct与union

编码运行环境:VS2012+Win32+Debug Win32既表示运行平台是Windows 32bits操作系统,又表示生成32bits的应用程序。

781

扫码关注云+社区

领取腾讯云代金券