资讯专栏INFORMATION COLUMN

进击JavaScript之(二)词法作用域与作用域链

denson / 1040人阅读

摘要:一作用域域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。概括的说作用域就是一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。

一、作用域

域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。想了解更多关于作用域的问题推荐阅读《你不知道的JavaScript上卷》第一章(或第一部分),从编译原理的角度说明什么是作用域。概括的说作用域就是一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。

1.1 块级作用域

在C、Java、C#等编程语言中,下面的语法报错(伪代码)

{
    var num = 123;
    {
        console.log( num );    // num => 123
     }
}
console.log( num );   //报错
1.2 JS的词法作用域

所谓的词法(代码)作用域,就是代码在编写过程中体现出来的作用范围,代码一旦写好,不用执行,作用范围就已经确定好了,这个就是所谓的词法作用域。

在JS中词法作用域的规则:

函数允许访问函数外部的数据

整个代码结构中只有函数可以限定作用域

作用规则首先使用提升规则分析

如果当前作用域中有了名字了,就不考虑外面的名字

例子1:

var num = 123;
function foo(){
    console.log( num );
}
foo();    //123

例子2:

if( false ){
    var num = 123;
}
console.log( num ); //undefined

例子3:

var  num = 123;
function foo () {
    var num = 456;
    function func(){
        console.log( num );
     }
     func();
}
foo();    //456
二、作用域链

只有函数才能制造作用域结构,那么只要是代码,至少有一个作用域,即全局作用域。

凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域,那么将这样的所有作用域列出来,可以有一个结构:函数内指向函数外的链式结构

例如:

function f1() {
    function f2() {
    }
}
var num = 456;
function f3() {
    function f4() {
    }
}

作用域链结构与DOM树结构很相似.

2.1 绘制作用域链

步骤:

看整个全局是一条链,即顶级链,记为0级链

看全局作用域中有什么成员声明,就以方格的形式绘制到0级链上

再找函数,只有函数可以限制作用域,因此从函数中引出新链,标记为1级链

然后在每一个1级链中再次往复刚才的行为

2.2 变量的访问(搜索)规则

首先看变量在第几条链上,在该链上看是否有变量的定义与赋值,如果有直接使用

如果没有到上一级链上找( n - 1 级链),如果有直接使用,停止继续查找。

如果还没有在此往上找… 直到全局链(0级),还没有就是is not defined

注意,切记:同级的链不可混合查找

绘制如下程序的作用域链

function f1() {
    var num = 123;
    function f2() {
        console.log( num ); 
     }
    f2();
}
var  num = 456;
f1();    //123

函数f1 和变量 num=456, 在0级链,而f1下又可以展开1级链,1级链上有num=123和函数f2。程序f1()调用进入左边1级链,而f1中又调用了f2函数,f2函数中console.log(num)可以看作在2级链,此时,程序会向这一条链向上查找,首先2级链没有num,向上到达1级链,刚好1级链上有num=123,所以就直接使用123,程序最后的结果就是打印123.

2.3 如何分析代码

在分析代码的时候切记从代码的运行角度上来分析,如果代码给变量赋值了,一定要标记到图中

如果代码比较复杂,可以在图中表示代码的内容,有时候还要将原型图与作用域图结合起来分析

分析如下代码:

var num = 123;
function f1() {
    console.log( num );
}
function f2(){
    var num = 456;
    f1();
}
f2();    //123

作用域链图:

首先把num=123,函数f1,函数f2画在0级链上。f1中只有一句console,画出一条1级链,f2也下画出1级链,链上有num=456和函数调用语句f1();

调用f2(),进入f2函数的作用域链,而在f2中又调用了f1函数,程序进入f1的作用域链,所以console.log(num)会在此链上查找是否存在num,没有,继续向上一级链查找,刚好在0级链上找到了num=123,所以f1函数中的console.log(num)就是123.

推荐阅读

进击JavaScript之(一)词法作用域与作用域链

进击JavaScript之(三)玩转闭包

进击JavaScript之(四)原型与原型链

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

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

相关文章

  • 进击JavaScript(三)玩转闭包

    摘要:为了更好的理解,在阅读此文之前建议先阅读上一篇进击之词法作用域与作用域链什么是闭包闭包的含义就是闭合,包起来,简单的来说,就是一个具有封闭功能与包裹功能的结构。在中函数构成闭包。 为了更好的理解,在阅读此文之前建议先阅读上一篇《进击JavaScript之词法作用域与作用域链》 1.什么是闭包 闭包的含义就是闭合,包起来,简单的来说,就是一个具有封闭功能与包裹功能的结构。所谓的闭包就是...

    cyixlq 评论0 收藏0
  • 进击JavaScript(四)原型与原型链

    摘要:每一个由构造函数创建的对象都会默认的连接到该神秘对象上。在构造方法中也具有类似的功能,因此也称其为类实例与对象实例一般是指某一个构造函数创建出来的对象,我们称为构造函数的实例实例就是对象。表示该原型是与什么构造函数联系起来的。 本文您将看到以下内容: 传统构造函数的问题 一些相关概念 认识原型 构造、原型、实例三角结构图 对象的原型链 函数的构造函数Function 一句话说明什么...

    XBaron 评论0 收藏0
  • 进击JavaScript(一)变量声明提升

    摘要:如下代码输出的结果是代码执行分为两个大步预解析的过程代码的执行过程预解析与变量声明提升程序在执行过程中,会先将代码读取到内存中检查,会将所有的声明在此进行标记,所谓的标记就是让解析器知道有这个名字,后面在使用名字的时候不会出现未定义的错误。 showImg(https://segmentfault.com/img/remote/1460000012922850); 如下代码输出的结果是...

    LeexMuller 评论0 收藏0
  • 你不知道的JavaScript上卷作用域与闭包·读书笔记

    摘要:的分句会创建一个块作用域,其声明的变量仅在中有效。而闭包的神奇作用是阻止此事发生。依然持有对该作用域的引用,而这个引用就叫做闭包。当然,无论使用何种方式对函数类型的值进行传递,当函数在别处被调用时都可以观察到闭包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:赋值操作的目标是谁? 比如: a = 2; RHS:谁是赋值操作的源头? 比如: conso...

    Raaabbit 评论0 收藏0
  • Javascript重温OOP作用域与闭包

    摘要:的变量作用域是基于其特有的作用域链的。需要注意的是,用创建的函数,其作用域指向全局作用域。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。 作用域 定义 在编程语言中,作用域控制着变量与参数的可见性及生命周期,它能减少名称冲突,而且提供了自动内存管理 --javascript 语言精粹 我理解的是,一个变量、函数或者成员可以在代码中访问到的范围。 js的变量作...

    JessYanCoding 评论0 收藏0

发表评论

0条评论

denson

|高级讲师

TA的文章

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