zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Generate Parentheses
    Length of Last Word
    Maximum Subarray
    Count and Say
    二分搜索算法
    Search Insert Position
    Implement strStr()
    Remove Element
    Remove Duplicates from Sorted Array
    Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/memeflyfly/p/14382462.html
Copyright © 2011-2022 走看看