你所不知道JS函数作用域

前言

js的作用域作为三大入门大山之一,其中蕴藏知识网络交错复杂。因为知识点多,所以可以借助测试题了解自己不足,再对应学习。内容也会不断更新内容的。。

JS的作用域

什么是作用域

作用域代表在那个范围内可以被使用,就比如中国的作用域就是整个中国,在这个范围内的变量(身份证)都可以使用。

作用域属性分类
  • 词法作用域(js的主要作用域类型):在js代码编译时就确定了作用域的范围。
var a = 2
function foo() {
  console.log(a) // 2
}
function bar() {
  var a = 3
  foo()
}
bar() 

foo函数定义时,就确定了函数的作用域在全局中,不会因为在bar函数中运行,就改变作用域。

  • 动态作用域 (了解):在js运行阶段才确定作用域的范围。
var obj = {a: 1, b: 2}
with (obj) {
  a = 'is_a',
  b = 'is_b'
  c = 'is_c'
}
console.log(obj, c)  // {a: 'is_a', b: 'is_b'}, 'is_c'

var a = 0
function foo(str, b){
  eval(str)  //严格模式不会改变作用域
  console.log(a, b)
}
foo('var a = 1', 2) // 1, 2
作用域范围分类
  1. 全局作用域

    在全局定义的变量或者在函数内部未使用var定义的变量都会分配到全局作用域中,自动挂载到window 的属性上面,并且 全局作用域中的变量不会执行垃圾回收过程 (全局污染)

function zxxFn () {
    zxxs = 2
}
var zxx = 1
console.log('zxx' in window)  //true
console.log(window.zxx) // 1
zxxFn()
console.log(zxxs) // 2
  • 全局变量都会赋值到 window 上面

  • 全局变量会在浏览器关闭时销毁

  • 一般采用老生代的垃圾处理机制(了解)

  1. 函数作用域(局部作用域)

    函数作用域是函数定义函数时生成的一个领域,在函数作用域里面的变量无法被函数外部访问(闭包除外),并且因为函数会在函数运行完毕时销毁函数作用域,使用函数作用域里面的变量会在函数运行完毕销毁。(可以使用某些方法让函数作用域不立即销毁)

    var a = 0, b = 0, c = 0, d = 0;
    function fun1(){
      var a = 1, b = 1, c = 1;
      function fun2(){
        var a = 2, b =2
        function fun3(){
          var a = 3
          console.log(a, b, c, d) // 3 2 1 0
        }
        fun3()
      }
      fun2()
    }
    fun1()
    
  • 变量在函数内声明,变量属于函数作用域。

  • 一般在函数运行完毕,函数作用域就会关闭

  • 函数作用域可以镶套

  • 一般采用新生代的垃圾处理机制,销毁迅速(了解)

  1. 块级作用域

    块级作用域和函数作用域差不多,只是两个作用的范围不一样,块级作用域是对应代码块的(大括号之间的内容),本身JS是不存在块级作用域的,但是在ES6里面出现了let、const产生块级作用域。

    {
        var i = 10
        let b = 3
    }
    console.log(i)   //10
    console.log(b)   //报错
    
    
作用域的特点
  1. 变量提升(预处理)

    在编译阶段要确定作用域首先要做的就是找到所有变量的声明,并利用相关机制将它们关联起来 ,在构建作用域时,会首先将var,function声明的变量或函数,进行变量提升处理,就是说提前声明。

    a()
    function a(){
      console.log(b)  //undefined
      var b=10
    }
    var a = undefined
    

补充:

| 概念  | 定义 |
| --- | :--- |
| 声明  | var a; 代表声明,现在的a还是undefined,但是告诉了编辑器存在a这个变量 |
| 赋值  | a=10; 对已经存在的变量存取值 |
  • 通过var定义的变量提升,而let和const进行的声明不会提升
  • 通过function关键字定义的函数会被提升,而函数表达式则不会提升。
  • 变量提示只是提升声明位置,并不会提升赋值,函数会提升整个函数
  • 函数的提升大于变量的提升
  • 对于同一个变量的多次提升,以最后一次为准备

扩展:为什么var变量可以声明多次,而let const只能声明一次?

var i=10
var i=20  //不会报错
let i=10
let i=20  //会报错

​ 因为var存在变量提示,就算多个变量声明,也是按照最后一个为准。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容