• JavaScript作用域与作用域链


    JavaScript作用域

    在JavaScript中,变量的作用域有全局作用域和局部作用域两种

    1.  全局作用域(Global Scope)

      在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

      (1)最外层函数和在最外层函数外面定义的变量拥有全局作用域,例如:

     1   var jotaro = "承太郎";
     2   function doSomething() {
     3     var joseph = "乔瑟夫";
     4     function innerSay() {
     5       console.log(joseph)
     6     }
     7     innerSay();
     8   }
     9   console.log(jotaro) //承太郎
    10   console.log(joseph) //error
    11   doSomething(); //乔瑟夫
    12   innerSay() //error

          (2)所有末定义直接赋值的变量自动声明为拥有全局作用域,例如:

    1   function doSomething() {
    2     var jotaro = "承太郎";
    3     joseph = "乔瑟夫";
    4     console.log(jotaro)
    5   }
    6   doSomething(); //承太郎
    7   console.log(joseph) //乔瑟夫
    8   console.log(jotaro) //脚本错误

    变量joseph拥有全局作用域,而jotaro在函数外部无法访问到。

          (3)所有window对象的属性拥有全局作用域

      一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。

    2.  局部作用域(Local Scope)  

      和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域,例如下列代码中的blogName和函数innerSay都只拥有局部作用域。

    1   function doSomething() {
    2     var joseph = "乔瑟夫";
    3     function innerSay() {
    4       console.log(joseph)
    5     }
    6     innerSay();
    7   }
    8   console.log(joseph) //脚本错误
    9   innerSay(); //脚本错误

     

    作用域链(Scope Chain)

     1   var name1 = "haha";
     2   function changeName() {
     3     var name2 = "xixi";
     4     function swapName() {
     5       console.log(name1);//haha
     6       console.log(name2);//xixi
     7       var tempName = name2;
     8       name2 = name1;
     9       name1 = tempName;
    10       console.log(name1);//xixi
    11       console.log(name2);//haha
    12       console.log(tempName);//xixi
    13     }
    14     swapName();
    15     console.log(name1);//haha
    16     console.log(name2);//xixi
    17     //console.log(tempName);
    18   }
    19   changeName();
    20   console.log(name1);//xixi
    21  //console.log(name2); 抛出错误:Uncaught ReferenceError: name2 is not defined
    22  //console.log(tempName);抛出错误:Uncaught ReferenceError: tempName is not defined

    上述代码中,一共有三个执行环境:全局环境、changeName()的局部环境和 swapName() 的局部环境。所以,

     1.函数 swapName()的作用域链包含三个对象:自己的变量对象----->changeName()局部环境的变量对象 ----->全局环境的变量对象

     2.函数changeName()的作用域包含两个对象:自己的变量对象----->全局环境的变量对象。

    就上述程序中出现的变量和函数来讲(不考虑隐形变量):

     1.swapName() 局部环境的变量对象中存放变量 tempName;

     2.changeName() 局部环境的变量对象中存放变量 name2 和 函数swapName();

     3.全局环境的变量对象中存放变量 name1 、函数changeName();

    在swapName()的执行环境中,在执行第5句代码时,解析器沿着函数 swapName()的作用域链一级级向后回溯查找变量 name1,直到在全局环境中找到变量 name1.并输出在控制台上。同样,在执行第6句代码时,解析器沿着函数 swapName()的作用域链一级级向后回溯,在函数changeName()的变量对象中发现变量 name2.通过代码对 name1 和 name2进行交换,并输出在控制台上,根据结果我们发现,这两个变量的值确实交换了。因此我们可以得出结论,函数的局部环境可以访问函数作用域中的变量,也可以访问和操作父环境(包含环境)乃至全局环境中的变量。

      在changeName() 的执行环境中,执行第15行和第16行代码时,可以正确地输出  name1 和 name2 和两个变量的值(调用了函数swapName(),所以俩变量的值已相互交换),那是因为 name1 在changName()的父环境(全局环境)中, name2 在他自己的局部环境中,即 name1 和 name2 都在其作用域链上。但当执行第17行代码是发生错误 tempName is not defined。因为解析器沿着 函数changeName()的作用域链一级级的查找 变量 tempName时,并不能找到该变量的存在(变量 tempName不在其作用域链上),所以抛出错误。因此,我们可以得出结论:父环境只能访问其包含环境和自己环境中的变量和函数,不能访问其子环境中的变量和函数。

      同理,在全局环境中,其变量对象中只存放变量 name1 、函数changeName();  解析器只能访问变量 name1 和函数 changeName(), 而不能访问和操作 函数 changeName() 和函数 swapName() 中定义的变量或者函数。因此,在执行第21行和第22行代码时抛出变量没有定义的错误。所以说,全局环境只能访问全局环境中的变量和函数,不能直接访问局部环境中的任何数据。

      其实,我们可以把作用域链想象成这样(里面的能访问外面的,外面的不能访问里面的,图为参考): 

      

    作用域链相关知识的总结:

    1.执行环境决定了变量的生命周期,以及哪部分代码可以访问其中变量

    2,执行环境有全局执行环境(全局环境)和局部执行环境之分。

    3.每次进入一个新的执行环境,都会创建一个用于搜索变量和函数的作用域链

    4.函数的局部环境可以访问函数作用域中的变量和函数,也可以访问其父环境,乃至全局环境中的变量和环境。

    5.全局环境只能访问全局环境中定义的变量和函数,不能直接访问局部环境中的任何数据。

    6.变量的执行环境有助于确定应该合适释放内存。

    引用文章:https://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html

        :https://www.cnblogs.com/buchongming/p/5858026.html

  • 相关阅读:
    [Silverlight]常见问题
    [C#]有趣的VS扩展DebuggerVisualizer
    [EF5.0CODE FIRST]多对一及自关联映射的处理
    自定义控件传值
    关于.Net中类型转换ToInt32
    SQL版整数转IP
    SQL2008 Merge关键字用法与简例
    SQL语句,同时返回结果集,输出参数的值及return值
    多线程与异步操作实现的探讨
    SQL Prompt4 破解版
  • 原文地址:https://www.cnblogs.com/memeflyfly/p/14382462.html
Copyright © 2020-2023  润新知