作用域

  技术一般水平有限,有什么错的地方,望大家指正。

  作用域就是变量起作用的范围。作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形成块级作用域。

  除了块级作用域,在函数外面声明的变量可以在任何一个地方被访问到,这些变量的作用域都是全局作用域,全局作用域中的变量可以再任何一个地方使用:

var a = "zt";
function fn1(){console.log(a);
}
function fn2(){console.log(a);
}
fn1();
fn2();

  在函数里面声明的变量只能在当前函数内使用,这些变量的作用域我们称为函数作用域,只在当前函数内有效:

function fn1(){var a = "zt";console.log(a);
}
function fn2(){console.log(a)
}
fn1();
fn2();//报错提示a没有定义

  函数内定义的变量只在当前函数内有效,在函数以外的地方是不能被访问到的,fn2函数内没有定义a,全局作用域中也没有a使用一个不存在的变量所以报错。

作用域链

  作用域是可以嵌套的比如在全局作用域里面创建一个函数,函数里面可以在创建一个函数,这样就发生了作用域的嵌套,作用域链可以把作用域链接起来。当使用一个变量的时候,会优先在当前作用域内去寻找变量,如果当前作用域内不存在就会去上层作用域去寻找一直到全局作用域,如果还不能找到变量就会报错。  

var a = "global";
function fn1(){console.log(a);
}
fn1();

作用域是静态的

  我们先看一个例子:

  var flag = "outer";function demo(){var flag = "inner";function inner(){console.log(flag);}return inner;}var fn = demo();fn();//inner

  var flag = "outer";function demo(){var flag = "inner";fn();}function fn(){console.log(flag);}demo();//outer

  通过这两个例子我们可以看出函数的作用域是静态的,一个函数不管在哪被调用,它的作用域都是声明时的作用域。函数的作用域在声明时就已经被创建,在调用函数时会去访问他已经创建的作用域。

闭包

  闭包在MDN中的定义为:闭包是指那些可以访问独立变量的函数,所以在定义上我们可以把所有的函数都看做是闭包。闭包即密闭的空间,我们可以很自然的想到函数,因为函数就会生成一个密闭的空间,如果函数想称为一个闭包只需要在使用一个外部变量即可(使用外部变量的函数就是闭包)。通过闭包可以给我们带来一些便利,就是可以在高等级的作用域使用低等级作用域中的变量:

  function demo(){var flag = "test";return function(){console.log(flag);}}demo()();

  我们把demo函数里面的函数通过return使其可以在外部使用,我们已经说过作用域都是静态的,这样我们在外部使用return的函数时,就可以看到我们在全局作用域中调用函数最后输出了demo函数里面的"test"。

  这样我们可以做一些更有意义的事:

  var data = [];function demo(){var data = [];return{add:function(a){data.push(a);},print:function(){console.log(data);}}}var tool = demo();tool.add(1);tool.add(2);tool.add(3);tool.print();//[1, 2, 3]

  我们可以利用demo函数里面的data来存储我们的信息而且不用担心它被破坏(demo里面的data被私有化),而且我们也可以在外部在声明一个同名的data来存储别的信息,这两个不会产生任何冲突。

  闭包也可以帮我们解决一些小问题:

  for(var i=0;i<4;i++){setTimeout(function(){console.log(i);});}

  我们预期的结果是打印当前循环的i值结果输出全是4。先解释一下出现这么情况的原因:JS是一种单线程的语言,而setTimeout是异步的,只有当我们的代码执行完成以后setTimeout的处理函数才会执行,而执行的时候i的值已经是4了所以最终的输出全是4。

  我们可以通过闭包来解决这一问题:

  for(var i=0;i<4;i++){(function(i){setTimeout(function(){console.log(i)})}(i))}

  闭包可以形成一个独立的作用域这样每次循环都会有一个独立的函数作用域,循环完成后虽然i的值仍然是4但是setTimeout的处理函数在寻找i的时候会优先找到作为参数的i,而每一个参数i都表示当次循环的i,利用闭包我们可以完美的解决这种问题。

  在我们实际开发的过程中,遇到这种情况我们就可以通过闭包来解决,我们所说的"这种情况"通常有三个特点:

  1.首先有一个循环

  2.循环里面会创建函数,并且函数是延后执行的

  3.这些延后执行的函数会使用一个共同的变量,并且这个共同的变量和当前的循环值有关系

  我们按照这个规律套一下上面的代码:

  循环有了,每次循环也会生成一个函数,这些函数也都是在循环完成后才能执行,而且每一个函数都使用共同的i,而i就是当前的循环值,正好符合我们的三个特点。我们通过(function(){}())这种方式(匿名函数自执行)来形成一个闭包达到我们预期的目的。

  更深层次的了解,可以在网上查阅相关资料。

转载自网络

转载于:https://www.cnblogs.com/wenJiaQi/p/6034138.html

JavaScript作用域闭包简述相关推荐

  1. 「注解」《你不知道的JavaScript(上卷)》第五章:作用域闭包

    启示 理解闭包可以看做是某种意义上的重生. 掌握闭包将会功力大增. JavaScript中闭包无处不在. 实质问题 闭包使得函数可以继续访问定义时的词法作用域. 现在我懂了 循环和闭包 在看懂for循 ...

  2. JavaScript作用域、上下文、执行期上下文、作用域链、闭包

      作用域.上下文.执行期上下文.作用域链.闭包是JavaScript中关键概念之一,是JavaScript难点之一,在应聘面试时必定会问到的问题,作为前端工程师必须理解和掌握.相信大家已经阅读了很多 ...

  3. Web前端Lec7-2 - Javascript作用域与闭包

    Lecture7-2 Javascript作用域与闭包 文章目录 Lecture7-2 Javascript作用域与闭包 7.4 JavaScript 作用域 7.5 JavaScript 变量 7. ...

  4. 前端进阶(第二期)- 作用域闭包笔记

    原文地址: 2-1 从作用域链谈闭包 2-2 JavaScript深入之闭包 2-3 深入javascript--作用域和闭包 JavaScript Closures Explained by Mai ...

  5. 深入理解javascript作用域系列第四篇——块作用域

    前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...

  6. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  7. JavaScript作用域链

    之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...

  8. 你想知道的关于JavaScript作用域的一切(译)

    原文链接: Everything you wanted to know about JavaScript scope 原文作者: Todd Motto JavaScript中有许多章节是关于scope ...

  9. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

最新文章

  1. php联系mysql配置_php支持mysql配置
  2. IPv6中的特殊地址
  3. 函数指针,以及用函数指针的好用之处(回调函数)
  4. Xmanager连接Linux桌面异常解决方案
  5. Spring Boot -Shiro配置多Realm
  6. Python笔记-沪深三百与茅台简单分析(2021年数据)
  7. Python编程教程:面向对象之高级特性!
  8. React全家桶构建一款Web音乐App实战(五):歌曲状态管理及播放功能实现
  9. 2017-12-28 Linux学习笔记
  10. win10安装tomcat7的安装与配置【详细教程】
  11. 百度AI图像处理—图像主体识别调用教程(基于Python3-附Demo)
  12. 使用 OpenGL 实现 RGB 到 YUV 的图像格式转换
  13. easymock 图片_小程序——使用Easy Mock
  14. linux内核网络协议栈--netif_receive_skb()函数(八)
  15. A detailed derivation for the Bias Variance tradeoff Decomposition
  16. XingGAN for Person Image Generation(人体姿势生成笔记)
  17. 虚拟机介绍与使用(VMware Workstation)
  18. 360度全方位解析死链接
  19. 怎么把英文文献转译为中文?
  20. 二分查找法及其四种变形(MATLAB)

热门文章

  1. 可能是第二好的 Spring OAuth 2.0 文章,艿艿端午在家写了 3 天~
  2. 一个老程序员的30年生涯回顾(译文)
  3. 如何设计真正高性能高并发分布式系统(万字长文)
  4. 对 Session 的深入探讨
  5. 简单易懂的自动驾驶科普知识
  6. 中国SaaS死或生之三:SaaS SCM能否上演绝地求生?
  7. struts2异常ognl.MethodFailedException: Method setId failed for object
  8. 数据结构-简单实现二叉树的先序、中序、后序遍历(java)
  9. java显式构造函数_C++中的显式构造函数
  10. dma访问主存时_STM32F103单片机(五)——DMA