专栏首页天天闭包初识

闭包初识

1.变量作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
看代码
  var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 999
另一方面,在函数外部自然无法读取函数内的局部变量。
Js代码
  function f1(){
    var n=999;
  }
  alert(n); // error
这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
Js代码
  function f1(){
    n=999;
  }
  f1();
  alert(n); // 999

2.如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。
那就是在函数的内部,再定义一个函数。
先看代码:
  function f1(){
    n=999;
    function f2(){
      alert(n); // 999
    }
  }
f2能访问到f1的变量
Javascript语言特有的“链式作用域”结构,子对象会一级一级地向上寻找所有父对象的变量。
所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

再看:
function f1(){
       var  n=888;
        function f2(){
           alert(n)
        }
        return f2;
    }
    var result = f1();
    console.log(result)
结果:
//f2(){
            console.log(n)
        }
//然后在代码后再执行如下代码,
  result();//888,其实就是f2函数调用,
综合来看就是在函数体f1外边调用了函数的局部变量

3.深度理解

 var name = "The Window";   
  var object = {   
    name : "My Object",   
    getNameFunc : function(){   
      return function(){   
        return this.name;   
     };   
    }   
};   
alert(object.getNameFunc()());  //The Window
解析:object.getNameFunc()得到的结果是内部的function,然后在自执行,此时this指向window

再看:

function outerFun()
{
 var a =1;
 alert(a);  
}
var a=3;
outerFun();
alert(a);
结果是 ?? .  
再看下面的代码:

function outerFun()
{
 //没有var 
 a =1;
 alert(a);  
}
var a=4;
outerFun();
alert(a);
结果为??他们两次的结果不一样,真是奇怪,为什么呢?

4.两种形式

a)函数作为返回值
eg:
    function f1(){
        var a =100;
        function f2(){
            console.log(a)
        }
        return f2
    }

  f1()();//100

b)函数作为参数
eg:
var num = 10;
    var f2 = function (x) {
        x = x > num ? x : num;
        console.log(x)
    };
    (function(f){
        var num=50;
        f(30)
    })(f2)   //30
值得注意的是:代码运行,得到

      var num = 50;
      f2(30)//执行时取得是window下的num值,因为f2在window下创建的

自由变量跨作用域取值时:要去创建这个函数的作用域取值,而不是“父作用域”;

5.用处

eg:
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
var btns = document.getElementsByTagName("button");
    for(var i =0;i<btns.length;i++){
        btns[i].onclick = (function () {
           console.log(i)
    })
    }
等到的结果是:4,4,4,4

for(var i =0;i<btns.length;i++){
        btns[i].onclick = (function (a) {
            return function () {
                console.log(a)
            }
        })(i)
    }
得到的结果是:0,1,2,3
所以:
 for(var i =0;i<btns.length;i++){
        btns[i].onclick = (function () {
             btns[a].style.background ="red"
            }
    }
//上述代码会报错;???
 for(var i =0;i<btns.length;i++){
        btns[i].onclick = (function (a) {
            return function () {
                btns[a].style.background ="red"
            }
        })(i)
    }
解析:
 for(var i =0;i<btns.length;i++){
        btns[i].onclick = change(i);

                function change(a) {
                    return function () {
                        btns[a].style.background ="red"
                    }
                }

    }
//就能实现点击变色

6.总结

f1()调用完成。按理说应该销毁掉f1()的执行上下文环境,但是这里不能这么做,
因为执行f1()时,返回的是一个函数。函数的特别之处在于可以创建一个独立的作用域。
而正巧合的是,返回的这个函数体中,还有一个自由变量a要引用f1作用域下的f1()上下文环境中的a。
因此,这个max不能被销毁,销毁了之后f2函数中的a就找不到值了。

因此,这里的f1()上下文环境不能被销毁,还依然存在与执行上下文栈中。
eg:
 function f1(){
        var a =100;
        function f2(){
            console.log(a)
        }
        return f2
    }
    f1()()//100

[详情参考](http://www.cnblogs.com/wangfupeng1988/p/3994065.html);

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • onload事件

    天天_哥
  • RegExp对象

    正则表达式描述了字符的模式对象。 当您检索某个文本时,可以使用一种模式来描述要检索的内容。RegExp 就是这种模式。 简单的模式可以是一个单独的字符。 ...

    天天_哥
  • 创建节点,碰撞消失效果

    天天_哥
  • 前端面试题库系列(1)

    // 浏览器解析css选择器的规则是从右向左的,这样会提高查找选择器所对应的元素的效率。

    李才哥
  • 微信设置 在浏览器中打开 用于下载app单页

    华创信息技术
  • 在Office应用中打开WPF窗体并且让子窗体显示在Office应用上

    在.NET主程序中,我们可以通过创建 ExcelApplication 对象来打开一个Excel应用程序,如果我们想在Excle里面再打开WPF窗口,问题就不那...

    用户1177503
  • MVC视图展现模式之移动布局解析-续集

    网站就必须用响应式布局吗?MVC视图展现模式之移动布局:http://www.cnblogs.com/dunitian/p/5213787.html 有人会疑问...

    逸鹏
  • kvm虚拟机的四种网络模式

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    suveng
  • 并行执行任务思考

    这篇文章由之前的并行执行任务发展而来,如何生成task,在之前的文章中,生成task方式如下:

    LiosWong
  • 微信小程序之富文本编辑组件editor结合RichText进行显示

    专注APP开发

扫码关注云+社区

领取腾讯云代金券