javascript 闭包

闭包的理解:

  简单来说,闭包就是在另一个作用域中保存了一份它从上一级函数或作用域取得的变量(键值对),而这些变量(键值对)是不会随着上一级函数的执行完成而被销毁。

  常用的闭包实现方法:

    1.函数闭包   

(function(){
    //函数闭包
})()

    2. try catch

try{

}catch(e){
     //catch闭包
}

    3.with 对象闭包

with(obj){
      //对象闭包
}

闭包的常用三种实现方法:

  找一个经典例子来演示闭包的实现方法。

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
     for(var i = 0,len = lists.length; i < len; i++){
        lists[i].onclick = function(){
            alert('点击的是:' + i);
        }
     }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

 

本来是想点依次点击li弹出0 1 2 3 4,可是弹出的却是4 4 4 4 4。

  注:onclick绑定的函数function(){alert('点击的是:'+i)}的作用域为对应的li对象,而函数里面的i的作用域为window,每次循环window.i的值都被重新赋值,因此,循环完后,i已经是4。所以点击哪个都是4。

 解决方法:

  1. 使用函数闭包

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
     for(var i = 0,len = lists.length; i < len; i++){
        lists[i].onclick = (function(){
            var num = i;
            return function(){
                alert('点击的是:' + num);
            }
        })()
     }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

 或者

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
     for(var i = 0,len = lists.length; i < len; i++){
        lists[i].onclick = (function(i){
            return function(){
                alert('点击的是:' + i);
            }
        })(i)
     }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

还可以用块级作用域来实现,将let 定义的变量具备块级作用域。在for循环中,每一次循环都会形成一个新的块级作用域,所以i不会被改变

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
     for(let i = 0,len = lists.length; i < len; i++){
        lists[i].onclick = function(){
            alert('点击的是:' + i);
        }
    }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

 2.使用try...catch语句构造的异常闭包

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
    for(var i =0,len = lists.length; i < len; i++){
        try{
            throw i;//自定义抛出异常
        }catch(e){
            lists[e].onclick = function(){
                alert('点击的是:' + e);
            }
        }
    }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

  3.使用with语句造成的对象闭包

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
  window.onload = function(){
    var lists = document.getElementsByTagName('li');
    for(var i =0,len = lists.length; i < len; i++){
        var obj = {value: i}
        with(obj){
            lists[value].onclick = function(){
                alert('点击的是:' + value)
            }
        }
    }
  }
</script>
<ul>
  <li id="list1">测试列表</li>
  <li id="list2">测试列表</li>
  <li id="list3">测试列表</li>
  <li id="list4">测试列表</li>
  <li id="list5">测试列表</li>
</ul>
复制代码

 

几个经典有用的实例:

  1.自加

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
    /**
    * 自加
    */
    addSelf = (function(){
        var i = 0;
        return function(){
            return i++;
        }
    })();
    alert(addSelf()) //0
    alert(addSelf()) //1
    alert(addSelf()) //2
</script>
复制代码

 

  2.阶乘

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
    /**
    * 阶乘
    */
    var factorial = function(n){
        if(n < 1){
            alert('invalid arguments');
            return 0;
        }
        if(n == 1){
            return 1;
        }else{
            return n*arguments.callee(n-1);
        }
    }
    alert(factorial(3)) //6
    alert(factorial(4)) //24
</script>
复制代码

 

  3.设置/获取 属性值

复制代码
<!doctype html>
<title>javascript闭包</title>
<meta charset="utf-8"/>
<script type="text/javascript">
    function User(properties){
        var self = this;
        for(var i in properties){
            (function(){
                var property = properties[i];
                self['get' + i] = function(){
                    return property;
                }
                self['set' +i] = function(value){
                    property = value;
                }
            })();
        }
    }
    //测试代码
    var user = new User({
        name:'Bob',
        age: '27'
    });
    
    alert(user.getname()) //Bob
    alert(user.getage()) // 27
    
    user.setname('Mike');
    alert(user.getname()) //Mike
    alert(user.getage()) // 27
    
    user.setage(22);
    alert(user.getname()) //Mike
    alert(user.getage()) // 22
</script>
复制代码

 实际开发中闭包的应用

  1.隐藏数据,只提供API

复制代码
// 闭包隐藏数据,只提供API
function createCache() {
        const data = {} //闭包中的数据,不被外界访问
       return {
              set(key,value){
                   data[key] = value
               },
               get(key){
                   return data[key]
                }
        }
}         

const c = createCache()
c.set('a',100)
c.get('a')               
复制代码

 

posted @   yangkangkang  阅读(218)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示