前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >闭包初识

闭包初识

作者头像
天天_哥
发布2018-09-29 13:56:11
2610
发布2018-09-29 13:56:11
举报
文章被收录于专栏:天天天天天天

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);

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.10.26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档