【3分钟带你学】 JS闭包

一、什么是闭包?

 var n=99;
 function f1(){
     console.log(n);
 }
 f1();    //99
    JavaScript中有两种作用域,全局作用域和局部作用域,函数内部可以直接读取全局变量。
函数 f1 可以读取全局变量 n。但是,在函数外部无法读取函数内部声明的变量。
 function f1() {
     var n = 99;
 } 
     f1();
 console.log(n);    //undefined
    但是, 有时我们却需要在函数外部访问函数内部的变量,正常情况下,这是办不到的,只有通过变通方法才能实现。
那就是在函数的内部, 再定义一个函数。
function f1() {
    var n = 99;
    var f2 = function() {
        console.log(n);
    }
    return f2;
} 
var f = f1();
f();

 

  上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。
这就是JavaScript语言特有的“链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然f2可以读取f1的局部变量, 那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
  闭包就是函数f2, 即能够读取其他函数内部变量的函数。
由于在JavaScript语言中, 只有函数内部的子函数才能读取内部变量, 因此可以把闭包简单理解成“定义在一个函数内部的函数”。
闭包最大的特点, 就是它可以“记住”诞生的环境, 比如f2记住了它诞生的环境f1, 所以从f2可以得到f1的内部变量。
 
在本质上, 闭包就是将函数内部和函数外部连接起来的一座桥梁;
 
二、垃圾回收机制(GC)及闭包

 
function f1( ) {
    var n = 99;
    console.log(++n);
}
     f1( ); //100
     f1( ); //100

  当我们在函数内部引入一个变量或函数时,系统都会开辟一块内存空间;
  还会将这块内存的引用计数器进行初始化,初始化值为0
  如果外部有全局变量或程序引用了这块空间,则引用计数器会自动进行+1操作
  当函数执行完毕后,变量计数器重新归零,系统会运行垃圾回收机制,将函数运行产生的数据销毁;
  如计数器不是 0 ,则不会清除数据;
  这个过程就称之为 "JS的垃圾回收机制" ;
但是,如果将代码该为闭包形式:
function f1() {
    var n = 99;
    function f2(){
    console.log(++n);
    }
 return f2;
}
var f = f1();
f(); //100
f(); //101
运行代码发现,函数调用一次,其变量 n 变化一次;
因函数f1被调用时,返回的结果是f2函数体,也就是说,f2函数被当作值返回给f1的调用者,
但是f2函数并没有在此时被调用执行,
所以整个 f1 函数体,无法判断子函数f2会对其产生何种影响,无法判断 变量n是否会被使用;
即使f1函数被调用结束, 整个f1函数始终保留在内存中,不会被垃圾回收机制回收;
 
闭包的作用
闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中.此外,还保护变量的安全,因为函数内的变量只能通过函数内部访问,其他途径不能访问。
注意, 外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。
因此不能滥用闭包, 否则会造成网页的性能问题。
 
闭包的应用实例
 
 
tab切换
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
* {
    padding-bottom: 0px;
    margin: 0px;
    padding-left: 0px;
    padding-right: 0px;
    font-size: 12px;
    padding-top: 0px;
}
BODY {
    padding-left: 20px;
    padding-top: 20px;
}
.wid240 {
    width: 242px;
    margin-bottom: 20px;
}
.wid180 {
    width: 182px;
}
.tab {
    border-bottom: #000 1px solid;
    border-left: #000 1px solid;
    border-top: #000 1px solid;
    border-right: #000 1px solid;
}
.tab UL {
    zoom: 1;
    clear: both;
}
.tab UL:after {
    display: block;
    height: 0px;
    visibility: hidden;
    clear: both;
    content: "";
}
.tab UL LI {
    text-align: center;
    line-height: 26px;
    width: 60px;
    display: inline;
    background: #000;
    float: left;
    height: 26px;
    color: #fff;
}
.tab UL LI.on {
    background: #fff;
    color: #000;
}
.tabList {
    border-bottom: #000 1px solid;
    border-left: #000 1px solid;
    height: 150px;
    border-top: #000 1px;
    border-right: #000 1px solid;
}
.tabList .one {
    padding-bottom: 10px;
    padding-left: 10px;
    padding-right: 10px;
    display: none;
    color: #ff0000;
    padding-top: 10px;
}
.tabList .block {
    display: block;
}
</style>
<meta name="GENERATOR" content="MSHTML 8.00.7600.16535">
</head>
<body>
<div class="wid240">
  <div class="tab">
    <ul>
      <li id="one1" class="on">one1 </li>
      <li id="one2">one2 </li>
      <li id="one3">one3 </li>
      <li id="one4">one4 </li>
    </ul>
  </div>
  <div class="tabList">
    <div id="cont_one_1" class="one block"> cont_one_1</div>
    <div id="cont_one_2" class="one"> cont_one_2</div>
    <div id="cont_one_3" class="one"> cont_one_3</div>
    <div id="cont_one_4" class="one"> cont_one_4</div>
  </div>
</div>
</div>
</body>
<script type="text/javascript">
        //获取li标签
        var lis = document.getElementsByTagName('li');
        //绑定悬浮事件
        for(var i=0;i<lis.length;i++) {
            lis[i].onmouseover = (function(index){
                return function() {
                    //切换div.one
                    var num = parseInt(index+1);
                    var div = document.getElementById('cont_one_'+num);
                    //判断
                    var divs = document.querySelectorAll('.one');
                    for(var i=0;i<divs.length;i++) {
                        divs[i].style.display = 'none';
                    }
                    div.style.display = 'block';
                }
            })(i);
        }
</script>
</html>

 

 
posted @ 2017-11-08 22:16  Martini  阅读(148)  评论(0编辑  收藏  举报