引言

       作用域与作用域链是JS应用中无时无刻不在影响程序运行的关键属性,但是由于它的不可见性,或者说它存在的过于普遍,简直就像空气一样。所以对它的谈及,都很简单,而理解起来也不复杂。



       但是由于它的重要性,对它做一个篇幅的说明,也是一件理所应当的事情。而且它其实也并没有理解上那么简单。



       本文对作用域及作用域链的说明,可能并不全面。笔者尽量以自身开发过程中的理解,做到表述全面。

1、执行环境

       按照《JavaScript高级程序设计》第3版中的定义——执行环境定义了变量或函数有权访问其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。

       对于环境的简单理解,可以理解为{}一个大括号就是一个执行环境。如{{}},就是包含关系的两个执行环境。而由于所有的函数和变量,最终都是通过最外围有对应的调用,才能最终实现运行,所以将最外围的执行环境定义为全局执行环境,在宿主为web浏览器时,全局执行环境就为window对象

       每个函数都有自己的执行环境。当执行程序进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将环境弹出,把控制权返回给之前的执行环境。之后,该环境因为执行完毕,随即被销毁。但有一个例外,全局环境将永远不会被销毁,直到程序被关闭,如关闭浏览器。

由上图我们清晰的看到JavaScript的两个阶段的执行流程。

2、作用域与作用域链

       作用域链和作用域是一个包含关系。当代码在一个环境中执行时,会创建变量对象的一个作用域链。而作用域链中,包含的就是一个个有序排列的作用域。作用域链的作用,就是保证执行环境中的变量和函数的有序访问

       每次的变量或函数声明,都会形成一个标识符(即变量名或函数名)。 作用域链中的向上查找,实际上就是标识符的查找。找到匹配的标识符,就调用它的值。

       作用域链中包含的每个作用域对象,其中都包含着它自身环境中可访问的变量或函数(script作用域中,为全部的变量和函数;函数作用域中,子函数调用父函数环境中的变量或函数会形成闭包,那么可访问变量就为闭包调用的变量)。换一种角度理解的话,这些环境中可访问的变量或函数就是标识符,是当前作用域中可通过作用域链向上查找的标识符。

       一大段的文字不光读起来枯燥,理解起来也困难。所以,stop talking,show code。


以函数为例

function test() {
let a = 1; //注释此行,保留其他a,c()打印2,并且作用域链失去闭包对象
let b = 0; return () => { //形成闭包环境
console.log(a);
}
} let a = 2; //注释此行及test中的a,c()打印3
window.a = 3; //注释全部a,报错 const c = test();
c(); console.dir(test);
console.dir(c);

以上代码,通过**3次注释**以及**chrome浏览器打印**,可以清晰的看到作用域与作用域链的形成及作用域链**按顺序查找**的特性

1)首先是闭包调用——所有a都不注释



由上图可以看出,此时作用域链中存在3个作用域对象。 按索引顺序为0—Closure闭包环境、1—Script标签环境、2—Global全局环境;

索引顺序就是标识符的查找顺序,所以当执行函数c()时,先在Closure闭包环境中查找,然后是Script标签作用域,最后是Global全局作用域。因为形成了闭包,那么标识符的查找肯定能在闭包环境中找到对应结果,所以打印1;

值得注意的一点是,Closure与Script作用域对象中,存储的标识符的不同。closure只存储调用值a = 1,并没有存储b = 0。而Script中将环境中的所有标识符都存在了对象中;

2)然后是取消闭包调用,改为Script标签作用域查找——注释test中的a = 1



由上图可以看出,此时作用域链中的Closure闭包作用域消失,只剩下2个对象0—Script标签环境、2—Global全局环境;

那么同样按索引顺序查找,找到了Script标签环境中的a = 2,没有继续寻找Global全局环境中的window.a = 3,最终打印2;

3)最后是Global全局作用域查找——注释test中的a = 1及script中的a = 2



与2)中情况对比,作用域链中的对象没有改变。但是Script对象中的标识符,随着a = 2被注释而消失

按索引顺序查找,找到了Script标签环境中没有a,继续寻找Global全局环境,最终找到window.a = 3,打印3;



函数test的打印,从始至终都是Script标签作用域及Global全局作用域。理解了c函数的作用域链,自然就明白了函数test的,所以不再展开赘述。

如有错误或阐述不充分之处,欢迎指正~

javascript精雕细琢(三):作用域与作用域链的更多相关文章

  1. 一步步学习javascript基础篇(2):作用域和作用域链

    作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = & ...

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

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

  3. JavaScript的作用域与作用域链

    作用域 作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.可以说,变量和函数在什么时候可以用,什么时候被摧毁,这都与作用域有关. JavaScript中,变量的作用域有全局 ...

  4. javascript作用域和作用域链摘录

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  5. JavaScript高级之词法作用域和作用域链

    主要内容: 分析JavaScript的词法作用域的含义 解析变量的作用域链 变量名提升时什么 一.关于块级作用域         说到JavaScript的变量作用域,与咱们平时使用的类C语言不同. ...

  6. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  7. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(转载 学习中。。。)

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  8. Javascript的作用域、作用域链以及闭包

    一.javascript中的作用域 ①全局变量-函数体外部进行声明 ②局部变量-函数体内部进行声明 1)函数级作用域 javascript语言中局部变量不同于C#.Java等高级语言,在这些高级语言内 ...

  9. JavaScript 作用域和作用域链

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

随机推荐

  1. 从数据库表导出为excel表格

    package com.test.daotest;   import java.io.FileNotFoundException; import java.io.FileOutputStream; i ...

  2. “吃神么,买神么”的第一个Sprint计划(第五天)

    “吃神么,买神么”项目Sprint计划 ——5.25  星期一(第五天)立会内容与进度 摘要:logo2出来了,修改过不一样的风格,组内总体评价可以,但是颜色要改,色调没注意,统一决定改成与背景色一致 ...

  3. Aspose 插件

    百度:Aspose Aspose.Cells.dll Aspose.Slides.dll Aspose.Words.dll

  4. EasyUi模糊匹配搜索框combobox

    现在项目当中很多已经应用了Jquery-easyUi这个界面框架了,所以,学习一点easyUI的常用工具就显得很重要了,现在介绍的就是我在项目中用到的easyUi的模糊匹配组合框combobox. c ...

  5. 使用node-webkit包装浏览器

    node-webkit简称nwjs:开源地址 https://github.com/nwjs/nw.js 参考博客 https://www.cnblogs.com/soaringEveryday/p/ ...

  6. cropper.js 超级好用的裁剪图片工具

    最近要做一个照片裁剪功能.就选用了cropper.js 代码如下:贴出来 <div class="container"> <div class="row ...

  7. Vue.js——60分钟browserify项目模板快速入门

    概述 在之前的一系列vue.js文章,我们都是用传统模式引用vue.js以及其他的js文件的,这在开发时会产生一些问题. 首先,这限定了我们的开发模式是基于页面的,而不是基于组件的,组件的所有代码都直 ...

  8. date format 参数表

    format 必需.规定输出日期字符串的格式.可使用下列字符: d - 一个月中的第几天(从 01 到 31) D - 星期几的文本表示(用三个字母表示) j - 一个月中的第几天,不带前导零(1 到 ...

  9. 增加kms计数

    @echo offset skms=10.15.68.62for %%i in (. . . . . . . . . . . . . . . . . . . . . . . . . .) do cal ...

  10. ZOJ3435_Ideal Puzzle Bobble

    把L,H,W分别减一就变成上面一个题目了. 不多说,也不召唤代码君了.