资讯专栏INFORMATION COLUMN

JavaScript中词法作用域、闭包与跳出闭包

lykops / 3163人阅读

摘要:是典型的词法作用域的语言,即一个符号参照到语境中符号名字出现的地方,局部变量缺省有着词法作用域。没有任何自己的局部变量,然而它可以访问到外部函数的变量,即可以使用父函数中声明的变量。通常,函数中的局部变量仅在函数的执行期间可用。

本文从属于笔者的JavaScript 入门与最佳实践系列文章,同时,本部分内容也归纳于笔者的我的校招准备之路:从Web前端到服务端应用架构这篇综述。

大部分人都会做错的经典JS闭包面试题
how-do-javascript-closures-work

Lexical Scope:词法作用域

functions are executed using the scope chain that was in effect when they were defined

一般来说,在编程语言里我们常见的变量作用域就是词法作用域与动态作用域(Dynamic Scope),绝大部分的编程语言都是使用的词法作用域。词法作用域注重的是所谓的Write-Time,即编程时的上下文,而动态作用域以及常见的this的用法,都是Run-Time,即运行时上下文。词法作用域关注的是函数在何处被定义,而动态作用域关注的是函数在何处被调用。JavaScript是典型的词法作用域的语言,即一个符号参照到语境中符号名字出现的地方,局部变量缺省有着词法作用域。此二者的对比可以参考如下这个例子:

function foo() {
    console.log( a ); // 2 in Lexical Scope ,But 3 in Dynamic Scope
}

function bar() {
    var a = 3;
    foo();
}

var a = 2;

bar();

看一个实例如下:

var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

该代码片最终输出的结果是:

I am just a local
Closure

闭包本身是含有自由变量的代码块,在JavaScript中我们常用的闭包则是本身的词法作用域与变量保留相结合的表现,首先回顾下一个基本的词法作用域的用法:

function init() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  displayName();
}
init();

函数 init() 创建了一个局部变量 name,然后定义了名为 displayName() 的函数。displayName() 是一个内部函数——定义于 init() 之内且仅在该函数体内可用。displayName() 没有任何自己的局部变量,然而它可以访问到外部函数的变量,即可以使用父函数中声明的 name 变量。注意,这里是直接执行外部的init函数,下面看一个闭包的例子:

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

运行这段代码的效果和之前的 init() 示例完全一样:字符串 "Mozilla" 将被显示在一个 JavaScript 警告框中。其中的不同 — 也是有意思的地方 — 在于 displayName() 内部函数在执行前被从其外围函数中返回了。这段代码看起来别扭却能正常运行。通常,函数中的局部变量仅在函数的执行期间可用。一旦 makeFunc() 执行过后,我们会很合理的认为 name 变量将不再可用。虽然代码运行的没问题,但实际并不是这样的。这个谜题的答案是 myFunc 变成一个闭包了。 闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。在我们的例子中,myFunc 是一个闭包,由 displayName 函数和闭包创建时存在的 "Mozilla" 字符串形成。

避免闭包

在真实的开发中我们常常会使用闭包这一变量保留的特性来传递变量到异步函数中,不过闭包也往往会使程序出乎我们的控制,譬如在下面这个简单的循环中,我们本希望能够打印出0~9这几个数:

for(var i = 0;i < 10;i++){
   setTimeout(()=>{console.log(i),1000})
}

不过所有输入的i的值都是10,这与我们的期望产生了很大的偏差。因此我们在部分情况下需要破坏闭包而获取真实的变量值。

将异步获取值保留到新增的闭包中

我们可以考虑加一层闭包,将i以函数参数形式传递给内层函数:

    function init3() {     
      var pAry = document.getElementsByTagName("p");     
      for( var i=0; i

或者在新增的闭包中将i以局部变量形式传递给内部函数中:

    function init4() {     
      var pAry = document.getElementsByTagName("p");     
      for( var i=0; i
将变量值保留到作用域之外

在DOM环境中,我们可以将变量值存储到要操作的DOM对象中:

    function init() {     
      var pAry = document.getElementsByTagName("p");     
      for( var i=0; i

也可以将变量i保存在匿名函数本身:

    function init2() {     
      var pAry = document.getElementsByTagName("p");     
      for( var i=0; i

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80118.html

相关文章

  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • 还担心面试官问闭包

    摘要:一言以蔽之,闭包,你就得掌握。当函数记住并访问所在的词法作用域,闭包就产生了。所以闭包才会得以实现。从技术上讲,这就是闭包。执行后,他的内部作用域并不会消失,函数依然保持有作用域的闭包。 网上总结闭包的文章已经烂大街了,不敢说笔者这篇文章多么多么xxx,只是个人理解总结。各位看官瞅瞅就好,大神还希望多多指正。此篇文章总结与《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 评论0 收藏0
  • JavaScript基础系列---闭包及其应用

    摘要:所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。所以本文中将以维基百科中的定义为准即在计算机科学中,闭包,又称词法闭包或函数闭包,是引用了自由变量的函数。 闭包(closure)是JavaScript中一个神秘的概念,许多人都对它难以理解,我也一直处于似懂非懂的状态,前几天深入了解了一下执行环境以及作用域链,可戳查看详情,而闭包与作用域及作用域链的关系密不可分,所...

    leoperfect 评论0 收藏0
  • 闭包详解一

    摘要:再看一段代码这样就清晰地展示了闭包的词法作用域能访问的作用域将当做一个值返回执行后,将的引用赋值给执行,输出了变量我们知道通过引用的关系,就是函数本身。 在正式学习闭包之前,请各位同学一定要确保自己对词法作用域已经非常的熟悉了,如果对词法作用域还不够熟悉的话,可以先看: 深入理解闭包之前置知识---作用域与词法作用域 前言 现在去面试前端开发的岗位,如果你的面试官也是个前端,并且不是太...

    cnio 评论0 收藏0
  • 《你不知道的javascript》笔记_作用闭包

    摘要:建筑的顶层代表全局作用域。实际的块级作用域远不止如此块级作用域函数作用域早期盛行的立即执行函数就是为了形成块级作用域,不污染全局。这便是闭包的特点吧经典面试题下面的代码输出内容答案个如何处理能够输出闭包方式方式下一篇你不知道的笔记 下一篇:《你不知道的javascript》笔记_this 写在前面 这一系列的笔记是在《javascript高级程序设计》读书笔记系列的升华版本,旨在将零碎...

    galaxy_robot 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<