大一菜鸡JavaScript学习之路(四)作用域与闭包

111 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。


作用域

  • 全局作用域,全局可用,可被局部作用域读取。
  • 局部作用域(函数作用域),局部变量只在函数体内可见,因此也称为私有变量。

定义作用域

  • 词法作用域:根据代码的结构关系确定作用域。

    • 静态的词法结构
    • JavaScript解析器主要根据词法结构确定每个变量的可见范围和有效区域。
  • 执行作用域:当代码被执行时,才能确定变量的作用范围和可见性。

    • 一种动态的作用域
    • 作用域会因为调用对象不同而发生变化。

JavaScript支持词法作用域,JavaScript函数只能运行在被预先定义好的词法作用域里,而不是被执行的作用域里。

因此,定义作用域实际上就是定义函数

作用域链

  • 作用域链是JavaScript提供的一套解决函数内部私有变量的访问机制。

  • JavaScript规定每一个作用域都有一个与之相关联的作用域链。

  • 在访问私有变量的过程中,会从链首的对象开始,然后依次查找后面的对象,直到在某个对象中找到与私有变量名称相同的属性

  • 如果在作用域链顶端(全局对象)中任然没有找到同名的属性,则返回undefined。

函数的私有变量

  • 函数参数
  • arguments
  • 局部变量
  • 内部函数
  • this(动态引用当前运行环境)

ES6 块级作用域

  • ES6引入了let 和 const
  • {}包裹的就是块级作用域
  • let 和 const 只能在块级作用域里作用

闭包

  • 定义闭包

    • 一个持续存在的函数上下文运行环境。
    • 内部函数引用外部函数的私有变量,同时内部函数又被外界调用。当外部函数被调用时,就形成闭包,这个函数也称为闭包函数。
    • function f(x){
         return function(y){
           return x+y;//如果return的是一个简单变量,那么c得到的只是一个简单的值,而不是函数的引用。
         };
         var c = f(5);//function(y)一直被引用。
         console.log(c(6))
      }
      
  • 使用闭包

    • //示例1
      var f = function(){
         var a = []
         return function(x){
            a.push(x);
            return a;
         };
      }();
      var a = f(1);
      console.log(a);
      var b = f(2);
      console.log(b); 
      //在上面示例中,通过外部函数设计一个闭包,定义一个永久的储存器。
      //当调用外部函数并生成执行环境之后,就可以利用返回的匿名函数,不断地向闭包体内的数组a传入新值,
      //传入的值会一直存在
      
    • //示例2
      function f(){
        var a = 1;
        b = function(){
          console.log("a="+a);
        }
        c = function(){
          a++;
        }
        d = function(){
          a--;
        }
      }
      </script>
      <button onclick = "f()">生成闭包</button>
      <button onclick = "b()">查看a</button>
      <button onclick = "c()">递增</button>
      <button onclick = "d()">递减</button>