• 第3章 第2节 作用域和作用域链


    作用域和作用域链

    什么是作用域?

    作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。

    具体分类:

    名称说明
    window/global Scope全局作用域
    function Scope函数作用域
    Block Scope块作用域(ES6)
    eval Scopeeval作用域(已经弃用)

    示例代码:

    // 全局作用域
    var a = 'andy';
    function test() {
        // 局部作用域
        var b = "Tim";
        console.log(b);
    }
    test(); // 输出 'Tim'
    console.log(a); // 输出 'andy'
    
    if (true) {
        // 这个 'if' 块语句没有创建一个块级作用域
    
        // name 变量处于全局作用域,因为由var关键字声明
        var name = 'Hammad';
        // likes 变量处于块级作用域因为由let关键字声明
        let likes = 'Coding';
        // skills 变量处于块级作用域因为由const关键字声明
        const skills = 'JavaScript and PHP';
    }
    
    console.log(Hammad); // 输出 'Hammad'
    console.log(likes); // Uncaught ReferenceError: likes is not defined
    console.log(skills); // Uncaught ReferenceError: skills is not defined
    
    

    理解前提

    • function的AO理解为“独立的仓库(作用域)”
    • 原理:利用AO、GO来解决作用域、作用域链相关所产生的一切问题
    • 函数也是一种对象类型,一种引用类型,有引用值
    • 函数有属性:test.name test.length test.prototype
    • 对象的有些属性是我们无法访问的,这些属性就是JS引擎内部固有的隐式属性(内部私有属性)
    • AO:函数的执行期上下文
    • GO:全局的执行期上下文

    原理说明

    (1)作用域:[[scope]](隐式属性)

    • 1、函数创建时,生成的一个JS内部的隐式属性。
    • 2、函数存储作用域链的容器,作用域链中存储AO、GO。
    • 3、当函数执行完成以后,旧的AO就销毁,当重新执行时,会重新生成新的AO。所以,AO是一个即时的存储容器。

    (2)作用域链
    把AO、GO从上到下排列起来,形成链式关系就是作用域链(scope chain)。

    执行过程

    (1)示例代码

    function a() {
        function b() {
            var b = 2; 
        }
        var a = 1;
        b();
    }
    var c = 3;
    a();
    
    

    (2)图解
    当a函数被定义时:
    image

    当a函数被执行时(前一刻):
    image

    当b函数被定义时:
    image

    当b函数被执行时(前一刻):
    image

    当b函数被执行结束后:
    image

    回归b函数被定义时的状态:
    image

    当a函数被执行结束时:
    image

    回归a函数被定义时的状态:
    image

    (3)总结-作用域的基础过程

    • 1、全局执行前一刻生成GO,同时函数声明已经定义
    • 2、全局执行(赋值),因为赋值是在执行的时候触发的。比如函数表达式赋值
    • 3、永远都是上级执行,下级被定义:全局执行的时候,全局函数已经被定义,全局函数执行的时候,内部的函数被定义
    • 4、当函数被定义的时候,已经形成了作用域[[scope]]、作用域链(scope chain),并放入GO
    • 5、当函数在执行的那一刻才会生成自己的AO
    • 6、函数在被定义的时候拿的是上级的作用域环境
    • 7、当函数执行完成以后,旧的AO就销毁,当重新执行时,会重新生成新的AO

    (4)结论

    • 1、每一个函数在的作用域上都有GO
    • 2、函数的AO存在作用域链的最顶端
    • 3、每个函数都有一个AO和GO,并且AO在GO的上面

    示例代码二

    function a () {
        function b () {
            function c () {
    
            }
            c();
        }
        b();
    }
    a();
    
    

    执行过程分析:
    image

    作用域与执行上下文

    许多开发人员经常混淆作用域和执行上下文的概念,误认为它们是相同的概念,但事实并非如此。

    我们知道JavaScript属于解释型语言,JavaScript的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

    解释阶段:

    • 词法分析
    • 语法分析
    • 作用域规则确定

    执行阶段:

    • 创建执行上下文
    • 执行函数代码
    • 垃圾回收

    JavaScript解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是this的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。

    作用域和执行上下文之间最大的区别是:
    执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变

    一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值

    给大家推荐一个好用的BUG监控工具Fundebug,欢迎免费试用!

  • 相关阅读:
    object-c中NSString与int和float的相互转换
    Keras
    TensorFlow白皮书
    java split进行字符串分割
    Java进行post和get传参数
    MySQL 导出数据
    解析xml并且导入mysql
    MySQL显示中文
    java使用sax解析xml
    mysql connection refused
  • 原文地址:https://www.cnblogs.com/szmtjs10/p/16110401.html
Copyright © 2020-2023  润新知