作用域与变量与声明提升

什么是作用域

当前的执行上下文。值和表达式在其中 "可见" 或可被访问到的上下文。如果一个变量或者其他表达式不 "在当前的作用域中",那么它就是不可用的。 作用域也可以根据代码层次分层,以便子作用域可以访问父作用域,通常是指沿着链式的作用域链查找,而不能从父作用域引用子作用域中的变量和引用。

当然,一个 Function 将生成一个闭包(通常是返回一个函数引用),这个函数引用从外部作用域(在当前环境下)可以访问闭包内部的作用域

  • ECMAScript5 只有全局作用域和函数作用域,ECMAScript6 之后才有块级作用域(let 、const)

全局作用域

定义的变量或函数在整个JavaScript程序中,都是可见的

var name = 'zyc'; // 全局变量

// 全局函数
function foo() {
    console.log(name);  //使用全局变量
}

foo(); // 运行打印: zyc

//全局函数
function bar(){
  //嵌套函数
   function getAge(){
     console.log(name);  //使用全局变量
   }
   getAge(); //运行打印:zyc 
   foo(); //运行打印:zyc 
}
bar();
console.log(name) //打印:zyc

函数作用域

定义在函数中的参数和变量或嵌套函数在函数外部是不可见的

 console.log(age);  //报错 Uncaught ReferenceError: age is not defined
 getAge();  //报错 Uncaught ReferenceError: getAge is not defined
 //全局函数
 function bar(){
        var age= 10;
        //嵌套函数
        function getAge(){
            console.log(age);
        }
        getAge(); //运行打印:10
    }
 bar();
 getAge();  //报错 Uncaught ReferenceError: getAge is not defined
 console.log(age); //报错 Uncaught ReferenceError: age is not defined

块级作用域

任何一对花括号 {} 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

 function bar() {
    var name = "zxy";
    {
        let age = 10;
        var kk = 'kk'
    }
    console.log(name); //打印输出 zxy
    console.log(kk);  //打印输出 kk
    console.log(age); //报错 Uncaught ReferenceError: age is not defined
}
bar();

变量与声明提升

  • var 关键字定义的变量可以在使用后声明,也就是变量可以先使用再声明(声明提升)
  • 使用 var 关键字声明的变量在任何地方都可以修改
  • let 、const关键字定义的变量则不可以在使用后声明,也就是变量需要先声明再使用。
  • let 、const 声明的变量只在 let 、const 命令所在的代码块 {} 内有效,在 {} 之外不能访问。(块级作用域)
  • let 、const都不能和它所在作用域内的其他变量或函数拥有相同的名称
  • const 用于声明一个或多个常量,声明时必须进行初始化,且初始化后值不可再修改
  • 在相同的作用域或块级作用域中,不能使用 const 关键字来重置 var 和 let关键字声明的变量
  • 在相同的作用域或块级作用域中,不能使用 const 关键字来重置 const 关键字声明的变量
  • 在相同的作用域或块级作用域中,不能使用 var 关键字来重置 let 关键字声明的变量
  • 在相同的作用域或块级作用域中,不能使用 let 关键字来重置 let 关键字声明的变量
  • 在相同的作用域或块级作用域中,不能使用 let 关键字来重置 var 关键字声明的变量
  • const 、let关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的
    var name = 'zyc'; // 全局变量

    // 全局函数
    function foo() {
        console.log(name);  //使用全局变量
    }

    console.log(foo) //运行打印 函数体
    foo(); // 运行打印: zyc

    //全局函数
    function bar() {
        var name = 2; //函数局部变量(属于当前函数体)
        foo(); // 这里调用全局函数,运行打印 zyc(调用的是栈内存中保存的方法属于全局作用域下不属于bar  函数的嵌套函数所以无法读取到bar函数定义的name)
    }

   console.log(bar) //运行打印 函数体
    bar();//全局函数调用

可以看成

{
   var name = 'zyc'; // 全局变量

    var foo;
    foo = function () {
        console.log(name);  //使用全局变量
    }
    var bar;
    bar = function(){
        var name = 2; //函数局部变量(属于当前函数体)
        foo(); // 这里调用全局函数,运行打印 zyc(调用的是栈内存中保存的方法属于全局作用域下不属于bar函数的嵌套函数所以无法读取到bar函数定义的name)
    }
    console.log(foo) //运行打印 函数体
    foo(); // 运行打印: zyc
    console.log(bar) //运行打印 函数体
    bar();//全局函数调用
 }

在如

   console.log(fn);
   fn(); 
    {
        fn();
        function fn() {
            console.log(10)
        };
        fn();
    }
    fn();

看做

  var fn;
  console.log(fn);
  fn();
  {
      fn = function(){
          console.log(10)
      };
      fn();
      fn();
  }
  fn();
  • 函数声明(函数名称) 类似于 var,即会提升到全局作用域或函数作用域的头部
  • 函数声明(函数整体) 还会提升到所在的花括号 {} 中的语句的头部

可以把整个script当做花括号{}

相关资料

JavaScript 变量
JavaScript let 和 const
JavaScript 声明提升
JavaScript 作用域
Scope
函数作用域, 块级作用域和词法作用域
函数提升与函数的块级作用域

你可能感兴趣的:(作用域与变量与声明提升)