JavaScript作用域闭包简述

时间:2023-02-23 15:53:11

JavaScript作用域闭包简述

作用域

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

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

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

JavaScript作用域闭包简述
JavaScript作用域闭包简述
var a = "zt";
function fn1(){
console.log(a);
}
function fn2(){
console.log(a);
}
fn1();
fn2();
JavaScript作用域闭包简述
JavaScript作用域闭包简述

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

JavaScript作用域闭包简述
JavaScript作用域闭包简述
function fn1(){
var a = "zt";
console.log(a);
}
function fn2(){
console.log(a)
}
fn1();
fn2();//报错提示a没有定义
JavaScript作用域闭包简述
JavaScript作用域闭包简述

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

作用域链

JavaScript作用域闭包简述

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

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

作用域是静态的

  我们先看一个例子:

JavaScript作用域闭包简述
JavaScript作用域闭包简述
  var flag = "outer";
function demo(){
var flag = "inner";
function inner(){
console.log(flag);
}
return inner;
}
var fn = demo();
fn();//inner
JavaScript作用域闭包简述
JavaScript作用域闭包简述
JavaScript作用域闭包简述
JavaScript作用域闭包简述
  var flag = "outer";
function demo(){
var flag = "inner";
fn();
}
function fn(){
console.log(flag);
}
demo();//outer
JavaScript作用域闭包简述
JavaScript作用域闭包简述

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

闭包

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

JavaScript作用域闭包简述
JavaScript作用域闭包简述
  function demo(){
var flag = "test";
return function(){
console.log(flag);
}
}
demo()();
JavaScript作用域闭包简述
JavaScript作用域闭包简述

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

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

JavaScript作用域闭包简述
JavaScript作用域闭包简述
  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]
JavaScript作用域闭包简述
JavaScript作用域闭包简述

  我们可以利用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。

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

JavaScript作用域闭包简述
JavaScript作用域闭包简述
  for(var i=0;i<4;i++){
(function(i){
setTimeout(function(){
console.log(i)
})
}(i))
}
JavaScript作用域闭包简述
JavaScript作用域闭包简述

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

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

  1.首先有一个循环

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

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

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

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

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

转载自网络

JavaScript作用域闭包简述的更多相关文章

  1. javascript作用域&lpar;Scope&rpar;&comma;简述上下文(context)和作用域的定义

    网页制作Webjx文章简介:这篇文章将正面解决这个问题:简述上下文(context)和作用域的定义,分析可以让我们掌控上下文的两种方法,最后深入一种高效的方案,它能有效解决我所碰到的90%的问题. 作 ...

  2. JavaScript作用域闭包(你不知道的JavaScript)

    JavaScript闭包.是JS开发project师必须深入了解的知识. 3月份自己曾撰写博客<JavaScript闭包>.博客中仅仅是简单阐述了闭包的工作过程和列举了几个演示样例,并没有 ...

  3. javascript作用域和闭包之我见

    javascript作用域和闭包之我见 看了<你不知道的JavaScript(上卷)>的第一部分--作用域和闭包,感受颇深,遂写一篇读书笔记加深印象.路过的大牛欢迎指点,对这方面不懂的同学 ...

  4. 读《你不知道的JavaScript&lpar;上卷&rpar;》后感-作用域闭包(二)

    github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...

  5. 《前端之路》之四 JavaScript 的闭包、作用域、作用域链

    04:JavaScript 的闭包 一.定义: 常规定义: 闭包的定义: 有权利访问外部函数作用域的函数. 通俗定义: 1.函数内部包含了函数.然后内部函数可以访问外部函数的作用域. 2.内部函数可以 ...

  6. JavaScript 作用域和闭包——另一个角度:扩展你对作用域和闭包的认识【翻译&plus;整理】

    原文地址 --这篇文章有点意思,可以扩展你对作用域和闭包的认识. 本文内容 背景 作用域 闭包 臭名昭著的循环问题 自调用函数(匿名函数) 其他 我认为,尝试向别人解释 JavaScript 作用域和 ...

  7. 关于Javascript作用域及作用域链的总结

    本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...

  8. JavaScript作用域链

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

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

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

随机推荐

  1. Ionic2系列-将beta升级到RC1

    国庆节前Ionic2发布了RC0版本,已经接近正式版了,前不久Angular2和TypeScript2也已经发布了正式版.详情请参考官方博客: http://blog.ionic.io/announc ...

  2. Spark相关下载

    HBase: http://hbase.apache.org/ Hadoop hadoop.apache.org spark http://spark.apache.org/

  3. 图解GCD

    线程.任务和队列的概念 异步.同步 & 并行.串行的特点 一条重要的准则 一般来说,我们使用GCD的最大目的是在新的线程中同时执行多个任务,这意味着我们需要两项条件: 能开启新的线程 任务可以 ...

  4. IE11出现&OpenCurlyDoubleQuote;&lowbar;&lowbar;doPostBack未定义”的解决办法。

    方法一:浏览器设置成兼容模式,这个是超级掩耳盗铃方法,你就没想过其他人也会出这个问题. 方法二.安装服务器版的.Net40的补丁.http://download.csdn.net/detail/565 ...

  5. rust haskell

    http://www.rust-lang.org <null>

  6. Allegro绘制PCB流程

    单位换算 1mil = 0.0254 mm 1mm = 39.3701 mil 默认情况下我们更倾向于使用mil单位绘制PCB板. 1 新建工程,File --> New... --> [ ...

  7. Linux 的 Shell

    一个:Shell 概念 shell 这个词是不奇怪,意思是 "壳" 这是间OS 用户和芯层之间的相互作用,在linux系统.用户可以通过命令终端.使用shell 命令向下传达他们的 ...

  8. Appium python自动化测试系列之自动化截图(十一)

    11.1 截图函数的正常使用 11.1.1 截图方法 无论是在手动测试还是自动化测试中场景复现永远是一个很重要的事情,有时候一些问题可能很难复现,这个都需要测试人员对bug有很高的敏感度,在一般的情况 ...

  9. 机器学习入门08 - 表示法 &lpar;Representation&rpar;

    原文链接:https://developers.google.com/machine-learning/crash-course/representation/ 机器学习模型不能直接看到.听到或感知输 ...

  10. 最全的libcurl库资源整理

    C++ 用libcurl库进行http 网络通讯编程 百度登陆协议分析!!!用libcurl来模拟百度登陆 C++使用libcurl做HttpClient 使用libcurl库进行HTTP的下载 li ...