js函数作用域

一、作用域

js中所有的变量,都有自己的作用域。当我们要访问变量时,必须要在规定的作用域下才能访问的到。首先作用域这个名词,它针对的是变量,产生于函数的层级关系。也就是说,因为函数的嵌套使用,在不同函数层级中声明的变量,才出现了不同的作用域。

二、作用域的形成

上边我们知道了,js中的作用域是因为函数的层级关系所形成的。要想研究作用域具体是如何形成的,就要深入了解一下js中函数的执行。通过阅读ECMAScript规范,并结合自己的一些测试。下面就来详细说一说js函数的执行。

首先在js中,对于每一个function来说,其实也是一个Object对象。在这些函数对象上,有一个隐式的[[scope]]属性,这个[[scope]]属性中存储的就是作用域链。这里所说的作用域链就是作用域的一个集合,刚刚我们提到,因为函数调用时,是有不同的层级关系的,每一层都有一个单独的作用域,这些作用域的集合,按照层级关系进行排列,就构成了这里的作用域链(也可以叫做执行期上下文的集合)。

1.既然作用域与函数有关,而js中函数一共有一下三种状态:

  • defined:函数定义,将函数自己加入到当前作用域中。
  • doing:执行前,创建一个作用域,并将这个作用域放入作用域的顶端。
  • finish:结束后,销毁这个作用域。

2.那么函数究竟如何生成作用域

  • 产生时间:函数执行的前一刻

  • 产生过程:

    • 构建AO,也就是新的函数作用域
    • 在函数作用域内声明,函数内变量和形参
    • 形参实参相统一
    • function函数声明补充、替换AO
  • 注意:

    • 在构建作用域的第二步中,变量包括let,const,var。对于var,在声明的同时被赋值为undefined。而let,const,只会注册一个这样的变量,但不会赋值,直到函数执行时,才会被真正的赋值。如果在赋值之前对其进行操作,就会触发暂时性死区。
    • 由于const是一个一次性赋值变量,所以在代码中声明const变量时同时需要赋值,script在执行之前会对基本语法做静态检测,对于const变量没有进行赋值时,就会直接报错。
    • 在构建作用域的第二步中,形参就会被赋值undefined。
    • 在构建作用域的第三步中,由于es6引入了形参的默认值。对于函数有传入参数时,就按照传入参数赋值;当没有传入参数时,就会按照默认值进行赋值,没有默认值,也没有传入参数,就是undefined。
    • 在构建作用域的第四步中,只有function显示声明,才会被补充声明。对于var a = function(){}声明的函数,a还是会被认定为undefined。

三、作用域的访问

之前我们提到作用域产生于函数嵌套,针对的是变量。那么变量访问与作用域的有什么关系呢?我们知道每个函数也是一个对象,对象的隐式的[[scope]]属性,就存储了函数调用过程中的所有作用域,在不同的作用域声明的变量,就存储在不同的作用域中。当我们需要操作一个变量的时候,就会从作用域中一层一层搜索这个变量。如果一直找到最上层依然没有找到相关的变量,就会抛出一些异常。

ReferenceError 同作用域判别失败相关,而 TypeError 则代表作用域判别成功了,但是对结果的操作是非法或不合理的。

你可能感兴趣的:(js函数作用域)