JS系列之二、作用域

184 阅读4分钟

一、概要

  • 作用域指的是您有权访问的变量集合。 引用自《w3school》

  • 执行环境(简称环境),是js的一个重要的概念。定义了变量或数据有权访问的其他数据。决定了他们各自的行为。
  • 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都存储在这个对象中,我们的代码无法编辑这个对象,但是解析器处理数据时会在后台使用它。
  • 在web浏览器中,全局的执行环境被认为是window对象
  • 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推进一个环境栈中,当函数执行之后,栈将其环境弹出,把控制权返回之前的执行环境。 概念性的内容是不直观且感受不到的,接下来我们伴着代码和概念一起梳理。
    <示例1>
function func() {
    var a = "我是变量";
}
func(); 
console.log(a);//Uncaught ReferenceError: a is not defined at <anonymous>:5:13

根据上面的示例,应该有一个基本的概念,作用域定义了变量的作用范围。说白一点就是一个变量在什么“范围”才起作用。如上例,超出了这个“范围”,就不起作用了。

二、作用域类型

  • JS作用域类型分为全局作用域局部作用域。观看下面示例 <示例2>
    var galbalA = '我是全局变量';
    function func() {
        var a = "我是局部变量";
        console.log(galbalA);// 我是全局变量
    }
    func(); 
    console.log(galbalA); // 我是全局变量
    console.log(a);//Uncaught ReferenceError: a is not defined at <anonymous>:5:13
    
    

    示例2为最外层定义的函数和变量,他们的作用域就是全局的,所以在func中执行对galbalA变量的引用程序是正常执行的。但是变量a就是局部作用域的,他只能在func内部起作用。所以在超出了a的作用域使用它就会报错。

  • 全局作用域
    1. 全局作用域不难理解,就是拥有全局作用域的变量(如上述<示例2>中的galbalA),在代码任何位置都可以被访问。那么全局变量所属的作用域就称之为全局作用域,。

    2. 什么情况下会产生全局变量?

    • 所有 window 对象的属性和方法 查看window属性和方法,正常的环境下,无论任何位置window对象的属性方法是可以被全局访问的 image.png
    • 最外层函数及最外层函数外定义的变量

    参考<示例2>的galbalA和函数func

    • 创建了变量字段但未声明的变量 <示例3>
      // 
      console.log(b);
      function func() {
          var a = "我是局部变量";
          b="未声明变量"
      }
      func(); 
      console.log(b); // 未声明变量
      
  • 局部作用域
    1. 函数作用域:在 JavaScript 函数中声明的变量,会成为函数的局部变量

image.png 2. 块级作用域

  • ES6之前是没有块级作用域的。
  • ES6出现后,对于块级作用域的使用,let、const,如下<示例4> <示例4>
{
var test1 = '1'
}
console.log(test1) // 1
{
let test2 = '2';
console.log('块内部console:',test2) //块内部console: 2
}
console.log('块外部console:',test2) //Uncaught ReferenceError: test2 is not defined
    at <anonymous>:9:27
  • 变量提升

JavaScript 中,函数及变量的声明都将被提升到函数的最顶部 <示例5>

console.log(name1)  //undefined 
var name1 = 'my name'
console.log(name1) //my name

上例子中,在未声明变量的上面执行打印不是报错而是打印undefined,说明变量出现了提升。隐式的完整代码应该是: <示例6>

// 在顶层提升变量
var name
console.log(name1)  //undefined 
// 这这里定义变量值
name1 = 'my name'
console.log(name1) //my name

四、作用域链

  1. 自由变量 在当前作用域使用但没有定义,继续向父级作用查找可以找到该变量声明定义的变量。
  2. 作用域链
    上面讲了自由变量及其查找方式,那么这种向父级作用域一级一级的查找,直到全局作用域的作用域关系,形成了作用域链

var a = 1; //--- 父父级作用域
function func1() { //--- 父级作用域
    var b = 2;
    function func2() {//--- 当前作用域
        var c = 33;
        console.log(a); // 父父级-自由变量
        console.log(b); // 父级-自由变量
        console.log(c); // 本级作用域的变量
    }
}

image.png

五、结语

  1. 时间关系整理这么多,后续会持续更新,有问题欢迎各位大佬能帮忙指正。