JavaScript:作用域&变量回收

JavaScript:作用域&变量回收

    • 局部作用域
      • 函数作用域
      • 块作用域
    • 全局作用域
    • 作用域链
    • 变量在浏览器模型中的位置
      • 浏览器模型
      • 全局变量的产生情况
      • 直接赋值全局对象与var全局对象的区别
    • 垃圾回收机制
      • 引用计数法
      • 标记清除法
    • 闭包
    • 变量提升&函数提升


作用域规定了变量能够被访问的范围,离开这个范围后,变量就无法访问。
在JavaScript中,作用域被分为局部作用域与全局作用域,本博客会简单为大家讲解作用域的基本规则后,深入拓展作用域的机制以及技巧。

局部作用域

函数作用域

函数作用域就是指:只能在函数内部访问的变量,外部无法直接访问的变量。
比如:

  function counter(x, y) {
    const a = x + y
    console.log(a) // 18
  }
  counter(10, 8)
  console.log(a)// 报错

在以上代码中,a变量在函数内部声明,等到出了函数再访问这个a,那么a就无法被找到了,最后会发生报错。
这是因为:
当一个函数被调用,其会创建自己的变量,当这个函数执行结束,其会销毁内部产生的变量,避免浪费内存

那么在函数内部声明的变量,出了函数就一定无法访问吗?
答案是不一定的,首先变量有三种定义形式:let/const/var,前两者是局部变量,var则是全局变量。:但是在函数中,let/const/var三者声明的变量在外部都不能访问
在函数中,还有一种声明变量的方式,就是直接使用没有声明的过的变量:

  function counter(x, y) {
    a = x + y
    console.log(a) // 18
  }
  counter(10, 8)
  console.log(a)// 正常

在上述代码中,a变量没有使用let/const/var三者之一声明,而且外部也没有a这个变量。此时,a变量不仅可以正常使用,而且可以被函数的外部访问,不会被销毁。
其根本原因是:如果一个变量不声明直接赋值(外部作用域也没有声明过),那么这个变量就会被直接挂在window对象下面,作为window对象的属性之一,根据标记清除法,这个变量不会被回收。如果你看不懂这段话也没关系,我们后面会说明标记清除法的机制。

到此,我们应该知晓以下重点:

  1. 函数内部声明的变量,在函数外部无法被访问
  2. 函数内部没有声明直接使用的变量,可以在外部访问
  3. 函数的参数也是函数内部的局部变量
  4. 不同函数内部声明的变量无法互相访问
  5. 函数执行完毕后,函数内部的变量实际被清空了

块作用域

JavaScript中使用{}包裹的代码称为代码块,代码内部声明的变量外部有可能无法访问。

  • 直接创建块级作用域
  {
    let age = 18;
    console.log(age); // 正常
  }
  
  // 超出了 age 的作用域
  console.log(age) // 报错
  • if 内部的块级作用域
  let flag = true;
  if(flag) {
    let str = 'hello world!'
    console.log(str); // 正常
  }
  
  // 超出了 age 的作用域
  console.log(str); // 报错
  • for内部的块级作用域
  for(let t = 1; t <= 6; t++) {
    console.log(t); // 正常
  }
  
  // 超出了 t 的作用域
  console.log(t); // 报错

还有非常多种方式会创建块级作用域,这里就不一一列举了。
那么我刚刚标红了有可能两个字,什么情况下在块级作用域声明的变量在外部可以访问呢?
其中一种情况函数作用域是一样的:没有声明就直接赋值的变量
这里不再做展示了,本博客后续会深入了解这个问题。

还有一种情况就是,在块级作用域内用var声明的变量

在早期的JavaScript中,并不存在letconst,也不存在块级作用域。当时的变量统一用var声明,所以后续推出的块作用域对var并没有影响。但是函数作用域是JavaScript早期就存在的概念,所以在上述函数作用域中,var定义的变量在函数外部也不能访问。
这也是此处要将块级作用域和函数作用域区分讲解的重要原因。有不少人认为函数也有{},所以其和块级作用域是一致的,但实际上并不是。由于历史问题,var同一时期的函数作用域会限制var,而后续出现的块级作用域并不会限制var

至此,块级作用域我们应知晓以下重点:

  1. let / const 声明的变量会产生块作用域,var 不会产生块作用域
  2. 不同块级作用域之间的变量无法互相访问
  3. 在块级作用域中没有声明直接赋值的变量,外部可以访问

全局作用域

你可能感兴趣的:(前端开发,javascript,开发语言,ecmascript)