zoukankan      html  css  js  c++  java
  • 执行上下文和作用域,作用域链

    • 给执行上下文环境下一个通俗的定义——在执行代码之前,把将要用到的所有的变量都事先拿出来,有的直接赋值了,有的先用undefined占个空。(变量的值是在执行过程中产生的确定的)
    •  javascript除了全局作用域之外,只有函数对象不创建作用域可以创建的作用域。(ES6新加了块级作用域 let)

    全局代码的上下文环境数据内容为:

    普通变量(包括函数表达式),

    如: var a = 10;

    声明(默认赋值为undefined

    函数声明,

    如: function fn() { }

    赋值

    this

    赋值

    如果代码段是函数体,那么在此基础上需要附加:

    参数

    赋值

    arguments

    赋值

    自由变量的取值作用域

    赋值

    作用域在函数定义时就已经确定了,而不是在函数调用时确定。作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的。例如,fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级。作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

    作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。

    一个例子:

    for (var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log( i);
        }, 1000);
    }
    
    console.log(i);

    如果我们约定,用箭头表示其前后的两次输出之间有 1 秒的时间间隔,而逗号表示其前后的两次输出之间的时间间隔可以忽略,代码实际运行的结果该如何描述?

    结果是5->5,5,5,5,5。因为i是个自由变量,当循环结束时,i已经等于5了,而setTimeout中的函数还未执行,等其执行时,获取的i为5。

    若想输出5->0,1,2,3,4,利用 JS 中基本类型(Primitive Type)的参数传递是按值传递(Pass by Value)的特征即可。

    方法一:IIFE

    for (var i = 0; i < 5; i++) {
        (function(j) {  // j = i
            setTimeout(function() {
                console.log(j);
            }, 1000);
        })(i);
    }
    
    console.log( i);

    方法二:

    var output = function (i) {
        setTimeout(function() {
            console.log(i);
        }, 1000);
    };
    
    for (var i = 0; i < 5; i++) {
        output(i);  // 这里传过去的 i 值被复制了
    }
    
    console.log(i);

    自由变量:

    在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。如下图 

    如上程序中,在调用fn()函数时,函数体中第6行。取b的值就直接可以在fn作用域中取,因为b就是在这里定义的。而取x的值时,就需要到另一个作用域中取。到哪个作用域中取呢?

    要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,—其实这就是所谓的“静态作用域”。

    作用域链:

    上面描述的只是跨一步作用域去寻找。

    如果跨了一步,还没找到呢?——接着跨!——一直跨到全局作用域为止。要是在全局作用域中都没有找到,那就是真的没有了。

    这个一步一步“跨”的路线,我们称之为——作用域链。

    我们拿文字总结一下取自由变量时的这个“作用域链”过程:(假设a是自由量)

    第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;

    第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;

    第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;

    第四步,跳转到第一步。

  • 相关阅读:
    .net 存储过程中的 output参数取值问题
    【从零开始学Servlet笔记】Servelet入门
    【从零开始学Servlet笔记】Web资源
    【从零开始学Servlet笔记】Http协议
    【从零开始学Mybatis笔记】SqlMapConfig.xml配置文件
    【从零开始学Mybatis笔记】Dao开发方法
    【从零开始学Mybatis笔记】Mybatis入门
    【从零开始学SpringMVC笔记】SpringMVC进阶
    【从零开始学SpringMVC笔记】SpringMVC与struts2不同
    【从零开始学SpringMVC笔记】参数绑定
  • 原文地址:https://www.cnblogs.com/JhonFlame/p/8022690.html
Copyright © 2011-2022 走看看