【3分钟带你学】JS闭包

【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)及闭包


先看一个demo

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函数始终保留在内存中不会被垃圾回收机制回收;

三、闭包的作用


闭包的最大用处有2个,

  1. 一个是可以读取函数内部的变量

  2. 另一个就是让这些变量始终保持在内存中.

    此外,还保护变量的安全,因为函数内的变量只能通过函数内部访问,其他途径不能访问即闭包可以使得它诞生环境一直存在;

    注意外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包, 否则会造成网页的性能问题。

下附一个实际应用案例 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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值