美文网首页
JavaScript作用域链

JavaScript作用域链

作者: 夜舞暗澜_3ea2 | 来源:发表于2018-05-17 19:35 被阅读0次

    作用域

    作用域就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期,在JavaScript中变量的作用域有全局作用域和局部作用域。在JavaScript中,变量的作用域有全局作用域局部作用域两种。

    显而易见,全局作用域就是大家都可以访问的部分,局部作用域就是只能在固定代码中访问的部分。
    另:浏览器中,全局作用域定义的变量都是window对象的一个属性。
    更详细的不提了,看文档。

    作用域链

    先上定义:

    作用域链决定了哪些数据能被函数访问。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。

    举个栗子:

    • JS的世界中,一个作用域只对自己直接包含的部分负责。而在一个作用域中查不到对应变量时,JS会转而向上寻求帮助,在更高级的、直接包含当前作用域的作用域中查找。
      var familyFund = 10000
      
      function Papa () {
        var papaMoney = 1000
        function Son() {
          papaMoney -= 100
          familyFund -= 100
          var sonMoney = 100
        }
        Son()
        console.log(papaMoney)
        console.log(familyFund) 
        console.log(sonMoney)
      }
      
      Papa()
      
      // 900
      // 9900
      // ReferenceError: sonMoney is not defined
      
      可以看到:直系后裔是可以直接调用祖先中定义的变量的。
    • 同样的,JS不会向下查找,也不会向同级查找。
      var familyFund = 10000
      
      function Papa() {
        var papaMoney = 1000
      }
      
      function Uncle() {
        Papa();
        console.log(familyFund)  
        console.log(papaMoney) 
      }
      
      Uncle()
      
      // 10000
      // ReferenceError: papaMoney is not defined
      
      这里可以很清楚地看到,定义位置同级的函数,无论调用位置在哪里,不告诉你就是不告诉你[摊手]
    • 然后问题来了:把所有钱的变量名设置成一样的,就能混着用了吗?
      var money = 10000
      
      function Papa() {
        var money = 1000
        function Son() {
          console.log('Son: '+money)
        }
        Son();
      }
      
      function Uncle() {
        console.log('Uncle: '+money)
      }
      
      Papa()
      Uncle()
      // Son: 1000
      // Uncle: 10000
      
      即使变量叫一样的名字,依然不是一样的东西。
      这个就是作用域链。

    复杂一点……

    还是那句话:这个值不在你的作用域下也不在你的作用域链中,那就是看不到,除非人家写个方法开放出来给你看。
    但是如果重复定义了,能不能本来能看的东西再拿出来看?
    可以啊,只要能说清楚是哪个就行啦~

    function Papa() {
      var money = 1000
    
      function Son() {
        console.log(money)
      }
    
      function Daughter() {
        var money = 500
        Son()
      }
      return Daughter
    }
    (Papa())()
    // 1000
    

    可以看到,Daughter中定义了自己的money是500,然后去调用了Son。Son直属于Papa,而且自己没有money,所以向上查找Papa中有这个值,就拿过来用了。

    注意!函数作用域与调用位置无关!只与声明位置有关!

    注意变量提升:

    如果一个函数运行在这个变量声明之前:

    function show(){ cosnole.log(abc) }
    show()
    var abc = 123
    

    它实际等同于:

    var abc = undefined // 变量提升
    function show(){ cosnole.log(abc) }
    show()
    abc = 123
    

    所以它会输出undefined。这就是为什么我们鼓励将变量声明统一写在函数前面。(好歹不会报错,知足吧~)

    相关文章

      网友评论

          本文标题:JavaScript作用域链

          本文链接:https://www.haomeiwen.com/subject/gkfidftx.html