理解了作用域链,闭包就不难理解了,所以本文主要谈一谈我对作用域链的理解。
 
关于JavaScript中变量的作用域,全局变量在程序中始终都有定义。局部变量在声明它的函数体内以及其内部所嵌套的函数内始终是有定义的。那么JavaScript是如何管理这些全局变量和局部变量作用域的呢,这就涉及到了作用域链。
作用域链相当于一个对象链表。链表的上的对象定义了这段script代码中的变量。如果要查找一个变量x,则会从这个作用域链的当前有权限访问的最底层对象开始找起,如果这个对象有一个名叫x的属性,则直接使用这个属性的值,如果没有找到继续向外层找其他的对象上是否有这个属性,直到找到作用域链的尾部,如果还没有,就返回undefined。
这里的“里层,外层”就是内部函数对包裹它的函数是不可访问的,提前说明一下有利于之后的理解。
 

在如下所示的JavaScript顶层代码中(不包含任何函数内定义的代码):
 <script>
'use strict';
var a = "";
function hello(){ }
</script>

它的作用域链只包含一个全局对象,作用域链组成如下:

在这段script代码中,由于只有全局变量,所以只有一个全局作用域链。当我们需要寻找a变量或者是hello函数的时候,就会去这个全局作用域链上找可访问的最底层对象(也是仅有的一个对象)——全局对象,然后在他的属性中找是否有a属性或者hello属性。


以上我们看了只有全局作用域链的情况,下面我们看函数体内有变量的情况,这时候就变成了两个作用域链,代码如下所示:

 <script>
'use strict';
var a = "";
function hello(){
var b = "";
console.log(b);
}
console.log(a);
hello();
</script>

此时我们注意到,hello函数的内部也定义了一个变量b,它的作用域链就变成了如下所示:

在这段script代码中,当执行到“console.log(a);”时,因为console.log()在全局环境之下执行,所以会直接去全局对象(可访问的最底层对象)中找名称为a的属性。那么如果我们在全局环境中加一句“console.log(b);”呢,他还是去全局对象中找,但是会发现找不到,返回undefined,因为hello函数内部的变量b是局部变量,它只有在hello函数局部对象中有。
所以当代码执行到“hello()”时,开始执行hello函数,执行到hello函数内部的“console.log(b);”时,就会先去hello函数局部对象中查找,如果找不到,才会去全局对象中查找,当然它在局部对象中就找到了。
那么如果我们在hello函数内部加一句“console.log(a);”它会先在局部对象中找,如果找不到就去全局对象中找。
所以如果我们继续在hello函数内部再定义一个函数inside(),同理,作用域链上又会对一个inside函数局部对象。它内部定义的变量同样是只存在于inside函数局部对象上,也就是仅inside函数内部可见。这种特性为之后的闭包奠定了基础。
 

我们再看下面一段代码:
 <script>
'use strict';
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
</script>

最后的checkscope()();会返回什么呢?答案是“local scope”。这个地方如果想要理解,就必须借助作用域链。首先我们看一下这段代码的作用域链:

我们把“checkscope()()”分成两部分执行:
    第一步:执行checkscope(),返回f函数,注意是函数不是结果。
    第二步:执行f()函数,这时候我们发现函数f()是在全局环境下执行的,所以理所当然的想到返回“global scope”。其实不是这样子,从作用域链就能看出,f函数在“checkscope函数局部对象”上,所以它的可访问的最底层对象是“checkscope函数局部对象”,所以执行到“return scope”时找这个scope变量时会首先在checkscope函数局部对象上找,立马就找到了,所以结果返回“local scope”,假设找不到,才回去全局对象上找。
注意,作用域链只能由里往外找,不能由外往里找,这也是“闭包”实现原则。到此,如果能理解作用域链,则闭包也就不难理解了。
 
 

有错误的地方欢迎指出讨论!

理解JavaScript中的作用域链的更多相关文章

  1. 深入理解JavaScript中的作用域和上下文

    介绍 JavaScript中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,我会尽我所能用最简单的方式来解释作用域.理解作用域将使你的代码脱颖而出,减 ...

  2. 深入理解JavaScript中的作用域、作用域链和闭包

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qappleh/article/detai ...

  3. 理解JavaScript中的作用域和上下文

    JavaScript对于作用域(Scope)和上下文(Context)的实现是这门语言的一个非常独到的地方,部分归功于其独特的灵活性. 函数可以接收不同的的上下文和作用域.这些概念为JavaScrip ...

  4. 理解JavaScript中的作用域

     什么是变量,什么是作用域? 变量:简单来说就是在特定时间内保存特定值的一个名字而已,由于不存在定义某个变量必须要保存某种数据类型值的规则,所以变量的值及其数据类型可以在脚本生命周期内任意改变,变量可 ...

  5. JavaScript中的作用域链原理

    执行环境 作用域链的形成与执行环境(Execution Environment)相关,在JavaScript当中,产生执行环境有如下3中情形: 1 进入全局环境 2 调用eval函数 3 调用func ...

  6. 理解 JavaScript 中的 this

    前言 理解this是我们要深入理解 JavaScript 中必不可少的一个步骤,同时只有理解了 this,你才能更加清晰地写出与自己预期一致的 JavaScript 代码. 本文是这系列的第三篇,往期 ...

  7. 深入理解javascript中执行环境(作用域)与作用域链

    深入理解javascript中执行环境(作用域)与作用域链 相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行 ...

  8. 认识Javascript中的作用域和作用域链

    作用域 只要写过java或者c#等语言的同学来说,相信一定能理解作用域的概念,在作用域的范围中,我们可以使用这个作用域的变量,对这个变量进行各种操作.可是,当使用Javascript的时候,相信很多的 ...

  9. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

随机推荐

  1. java设计模式-----22、状态模式

    概念: State模式也叫状态模式,是行为设计模式的一种.State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样. 根据这个概念,我们举个例子 public c ...

  2. Java线程分析

    一.Java线程的生命周期中,存在几种状态.在Thread类里有一个枚举类型State,定义了线程的几种状态 public enum State { NEW, RUNNABLE, BLOCKED, W ...

  3. 自定义高级版python线程池

    基于简单版创建类对象过多,现自定义高级版python线程池,代码如下 #高级线程池 import queue import threading import time StopEvent = obje ...

  4. Tomcat启动报错:org.apache.catalina.LifecycleException: Failed to start component...java.util.zip.ZipException: error in opening zip file

    1.项目环境 IntelliJ IDEA2018.1.6 apache-tomcat-8.0.53 基于springboot开发的项目 maven3.5.3 2.出现问题 从svn同步下项目 启动to ...

  5. webpack打包小图片时进行Base64转码

    关于base64 优点: base64就是一串字符串码表示的图片,在加载页面和js时一块加载出来,减少了加载图片时的http请求.加载一张图片时会发起一次http请求,http请求每次建立都会需要一定 ...

  6. HTML页面局部刷新

    /.事件响应刷新:有请求才会刷新 1.通过JS HTML DOM或jQuery获取HTML元素,通过DOM方法或jQuery方法监听页面事件,获取用户请求: 2.通过Ajax将用户请求提交至服务器,服 ...

  7. ubutu强制关闭应用程序的方法

    1.打开终端,输入命令 top 2.查看应用程序PID号,比如是8080 3.然后终端输入 kill 8080 ,行了

  8. C语言中使用的地址是真实的物理地址吗?

    设置程序基址固定:关闭程序基地址改变. 在vs中编写代码如下: #include <stdio.h> int main(){ int a = 5; printf("a的内存地址是 ...

  9. 常用的第三方模块 chardet url

    chardet 字符串编码一直是令人非常头疼的问题,尤其是我们在处理一些不规范的第三方网页的时候.虽然Python提供了Unicode表示的str和bytes两种数据类型,并且可以通过encode() ...

  10. jquery 绑定事件 获取方式 --------------data event 获取

    //绑定事件 bind event $("body").on("click",function(){ console.log("in") } ...