作用域、执行环境、闭包(四)

本文也同步发表在我的公众号“我的天空

 

 

上一期我们已经介绍了闭包,由于闭包可以延长函数内部的变量的生存周期,因此我们可以将不需要暴露在全局的变量封装成函数的内部变量,从而避免代码污染。

 

譬如要实现一个简单的累加器,为了保存每次累加的结果,因此声明了一个全局变量total,代码如下:

 

var total=0;
function add(t){
    total =t;
    alert(total);
}
total=2;
add(3);        //显示5
add(5);        //显示10
add(1);        //显示11

 

但是在实际开发中,应尽量避免全局变量,因为全局变量可以在代码的任何地方被调用,假设在其他地方,不小心更改了total的值的话,我们这个累加器就会出问题了。由于total值是只供函数add()使用的,因此希望total能被封闭在函数add()的内部,这样,就无法从外部来改写它了,我们使用闭包来实现,代码如下:

 

function add(s){
    var total=s;
    return function(t){
        total =t;
        alert(total);
    }
}
var a=add(2);
a(3);        //显示5
a(5);        //显示10
a(1);        //显示11

 

通过闭包,将变量total封闭在函数add()中,外部无法访问到,这样就避免了被其他代码随意改写的可能性。

 

由于闭包会将封闭在函数内部的局部变量赋予类似于全局变量的效果,因此在有些场景下需要特别注意,尤其是涉及到循环遍历,来看以下代码:

 

function createArray(){
    var result=new Array();
    for (var i=0;i<3;i ){
        result[i]=function(){
            return i;
        }
    }
}

 

这是一个创建数组数组的函数,从表面上看,每个函数应该都返回自己的索引值,因此创建的数组中,每个元素应该包含如下函数:

 

result[0]:function(){return 0}
result[1]:function(){return 1}
result[2]:function(){return 2}

 

但是实际上,数组中的每个元素只是包含:function(){return i},也就是说,当该函数执行完毕后,返回的是这样一个数组:

 

{
    function(){return i},
    function(){return i},
    function(){return i}
}

 

而变量i由于存在于一个返回函数中,形成了闭包,所以当createArray()执行完毕后,其执行环境不会被销毁,变量i得以保留,并且其值为3(这点很重要)。

 

因此,当我们使用createArray()来创建数组时,得到的效果就不是我们的预期,弹出的都为“3”:

 

var a=createArray();
for(var z=0;z<a.length;z ){
    alert(a[z]());    //均显示为3
}

 

实际上该代码无非就是重复执行三遍以下代码:

 

alert(function(){return 3}());


那么为了达到我们的预期,应该将createArray()函数做如下修改:

 

function createArray(){
    var result=new Array();
    for (var i=0;i<3;i ){
        result[i]=function(z){
            return function(){
                return z;
            };
        }(i)
    }
}

 

分析以上代码,我们将一个自执行函数返回给了数组元素,在赋值的时候,变量z就是在赋值的那个时刻的i值,那么返回的数组中的元素便包含我们预期的函数:

 

result[0]:function(){return 0}
result[1]:function(){return 1}
result[2]:function(){return 2}

 

再一次执行以下代码,显示就正常了:

 

var a=createArray();
for(var z=0;z<a.length;z ){
    alert(a[z]());    //依次显示0、1、2
}


一定要注意的是,我们是把一个函数赋予了数组中的元素,而不是单个的值。因为在实际的应用中,返回函数的话,我们就可以在函数内做更多的事情。

 

看以下的实现,html有四个p标签和4个div标签,当单击div标签时相应的p标签更改颜色,请注意这是一个面试中非常容易遇到的题目,代码如下:

 

<body>
  <p>p1</p><p>p2</p><p>p3</p><p>p4</p>
  <div>div1</div><div>div2</div><div>div3</div><div>div4</div>  
 </body>

  <script>
     var d=document.getElementsByTagName("div");
       for(var i=0;i<d.length;i ){
         d[i].οnclick=function(num){
             return function(){
                document.getElementsByTagName("p")[num].style.color="red";
             };
         }(i);
       }
 </script>

 

如果直接写成以下代码的话,那么无论你单击哪个div,程序总是会报错,因为此时i的值为4,所以document.getElementsByTagName("p")[4]这个元素并不存在,导致引用错误。

 

   for(var i=0;i<d.length;i ){
        d[i].οnclick=function(){
          document.getElementsByTagName("p")[i].style.color="red";
      };
   }

 

最后我们要注意的是当需要返回函数内部的多个变量时,便不能采用返回匿名函数的方式了,可以采用以下的形式:

 

function setpepole(){
    var name="李四";    
    var age=31;
    return {
        getname:funcion(){
            return name;    
        },
        getage:function(){
            return age;
        }
    }
}
var a=setpepole();
alert(a.getname());     //显示“李四”
alert(a.getage());      //显示31

 

闭包系列就到此全部结束了!

 


更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363896.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

今天发布了一个新的网站矩阵www.wimatrix.cn

关于科技生活新知的&#xff0c;digg类型&#xff0c;欢迎朋友们来访问&#xff0c;并提出宝贵的意见网址是 http://www.wimatrix.cn 转载于:https://www.cnblogs.com/liugod/archive/2007/09/29/910637.html

[Bzoj2243][SDOI2011]染色(线段树树剖)

题目链接&#xff1a;https://www.lydsy.com/JudgeOnline/problem.php?id2243 线段树树链剖分&#xff0c;在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色&#xff0c;向上更新时需要判断左区间的右边界是否和右区间的左边界相等。在剖分求LCA的过程中需要在求…

php static_castunsigned int,C++ static_cast、dynamic_cast、const_cast和reinterpret_cast(四种类型转换运算符)...

上节讲到&#xff0c;隐式类型转换是安全的&#xff0c;显式类型转换是有风险的&#xff0c;C语言之所以增加强制类型转换的语法&#xff0c;就是为了强调风险&#xff0c;让程序员意识到自己在做什么。但是&#xff0c;这种强调风险的方式还是比较粗放&#xff0c;粒度比较大&…

NetBeans IDE 8.0和Java 8的新功能

NetBeans IDE 8.0已发布&#xff0c;还为Java 8技术提供了新功能。 它具有用于与Java SE 8&#xff0c;Java SE Embedded 8和Java ME Embedded 8配合使用的代码分析器和编辑器。IDE还具有新的增强功能&#xff0c;这些功能进一步改善了其对使用PrimeFaces对Maven和Java EE的支持…

AngularJS(九):路由

本文也同步发表在我的公众号“我的天空” AngularJS路由 AngularJS路由可以让我们通过不同的URL访问不同页面&#xff08;似乎是废话&#xff09;&#xff0c;其价值主要体现在单页面的web应用中&#xff08;single page web application&#xff0c;SPA&#xff09;&#xff0…

(转)Oracle中实现行列转换的方法

(转自)http://blog.csdn.net/Torrice/archive/2006/01/25/587986.aspx 我们在写SQL语句的时候经常需要用到行与列的转换问题&#xff0c;对于一个新手来说可能比较困难&#xff0c;其实你只要能够熟练运用Decode和Sum函数&#xff0c;这个问题就迎刃而解. Create table tes…

[C3W2] Structuring Machine Learning Projects - ML Strategy 2

第二周&#xff1a;机器学习策略&#xff08;2&#xff09;&#xff08;ML Strategy&#xff08;2&#xff09;&#xff09; 误差分析&#xff08;Carrying out error analysis&#xff09; 你好&#xff0c;欢迎回来&#xff0c;如果你希望让学习算法能够胜任人类能做的任务&a…

mysql语句执行顺序图示

转载于:https://www.cnblogs.com/whalesea/p/10382227.html

玩Java 8 – Lambda和并发

因此Java 8不久前发布&#xff0c;具有许多功能和更改。 我们所有的Java狂热者一直在等待这个历史&#xff0c;从他们最初宣布Java 7的所有强大功能开始一直到最终被取消。 我最近才有时间实际开始给它一个真实的外观&#xff0c;我将我的家庭项目更新到了8个&#xff0c;我不…

用matlab 拟合实数解,求大神指点matlab用拟合的方式解延迟微分方程组参数

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼dy(1)-k*y(1)*y(2);dy(2)Z(3,1)-a*y(2)-q*y(2);dy(3)k*y(1)*y(2)-Z(3,1);dy(4)a*y(2);dy(5)q*y(2);t12345678910111213141516171819202122232425262728293031323334353637383940y208563475657545454535252515150504948484747464545…

AngularJS(三):重复HTML元素、数据绑定

本文也同步发表在我的公众号“我的天空” 重复HTML元素 在前端的页面编写中&#xff0c;我们会经常遇到重复HTML元素&#xff0c;譬如绘制表格、菜单等&#xff0c;如以下代码显示一个简单的li列表&#xff1a; <body> <ul id"ul_cities"> </ul…

hyper-v下的ubuntu虚拟机分辨率修改

修改/etc/default/grub sudo vim /etc/default/grub 改变前: GRUB_CMDLINE_LINUX_DEFAULT"quiet splash" 改变后: GRUB_CMDLINE_LINUX_DEFAULT"quiet splash videohyperv_fb:1920x1080" 更新grub配置 sudo update-grub 重启即可生效 sudo reboot 转载于:ht…

gopacket 在 windows 上面遇到的问题

前阵子有个需求是使用 golang 抓包改包&#xff0c;我用到了 gopacket 这个包&#xff0c;但是出了一些小问题。 我按照网上的方法进行使用 OpenLive 抓包&#xff0c;发现并不行&#xff0c;报错 error open adapter 啥啥啥。 经过调试发现根本找不到这个网卡&#xff0c;需要…

使用表中的数组数据类型

在这篇文章中&#xff0c;我想跟进我以前关于Oracle集合数据类型的文章 &#xff0c;并且我将集中精力使用af&#xff1a;table组件中的oracle.jbo.domain.Array属性。 因此&#xff0c;在我的数据库中&#xff0c;我具有以下SQL类型&#xff1a; create or replace type var…

最伟大最不可思议最令人感动的父亲

转载于:https://www.cnblogs.com/chenou/archive/2007/10/23/935014.html

关于数据库名、实例名

最近因看到论坛有人问起这方面的东西&#xff0c;将自己的理解加上查阅相关资料整理如下&#xff0c;如果不全或不当的地方&#xff0c;望指正并补全它。 数据库名(DB_NAME)、实例名(Instance_name)、以及操作系统环境变量(ORACLE_SID) 在ORACLE7、8数据库中只有数据库名(db_…

linux 文件inode,linux文件系统-inode学习整理

linux文件系统-inode学习整理介绍linux文件系统可讲的模块有很多&#xff0c;包括文件系统整体架构、文件系统分类、虚拟文件系统以及文件系统存储结构等等&#xff0c;本文主要介绍的是文件系统的存储结构&#xff0c;也就是本文的重点-inode。文件存储结构首先从开天辟地开始…

操作方法:Maven的Spring Boot和Thymeleaf

Spring Boot是一款很棒的软件&#xff0c;可让您在几秒钟内引导Spring应用程序。 它确实有效。 尽可能少的配置即可上手。 而且仍然可以更改默认值。 让我们看看用Thymeleaf和Maven引导Spring MVC并在IntelliJ中使用它是多么容易。 Spring MVC Thymeleaf与Maven的基本设置 确…

csharp: 百度语音合成

public string API_id "3333"; //你的IDpublic string API_record null; public string API_record_format null; public string API_record_HZ null;public string API_key "geovindu"; //你的KEYpublic string API_secret_key "geovindu"…

20080408 - VS2003 中 Jscript 文件中文乱码问题

在 VS2003 中新建 Jscript 文件中使用中文时&#xff0c;如果和网页的编码不一致&#xff0c;有可能会出现中文乱码问题。 而 VS2003 的Web页面默认是用 UTF-8&#xff0c;这是多语的首选方案。 但 VS2003 产品的本地化工作可能做得不到位&#xff0c;在其中新建的 Jscript 文件…