函数与作用域

 

由于作用域相关的东西太多,所以拆分成多个章节

 

一、作用域概述

 

二、标识符与作用域

 

三、全局和模块作用域

 

四、函数作用域

 

五、块作用域

 

六、作用域 与 this

 

1.函数的声明与作用域

这个标题有点奇怪,函数的声明貌似和作用域没有关系,当然它也确实和函数本身的作用域没有关系,但是大家都知道,js是词法作用域,也就是说,

函数在哪里声明的,那么它的outerEnv(外部或者说父级作用域)就是在那里,所以说函数的声明和其outerEnv有关系,那他是怎么实现的呢?

首先,我们想想,函数是什么?在执行函数声明的时候,js引擎会把它转为为含有一些特殊字段的对象,所以这里划重点:函数是一个对象

注:特殊字段包含:constructor, call, sourceCode等等

既然函数是一个对象,那么可以设置值,js在执行的时候,就会把当前的作用域做为其outerEnv,那么无论这个函数在哪里引用,他的outerEnv都是固定的,

在其声明的时候就创建好了,也就实现了我们所说的词法作用域

 

2..执行无默认值的函数流程

首先,我们来看看当函数执行的时候,代码执行一般过程:

1.执行函数会创建执行上下文context,而根据es规范中对context的字段说明,其包含两个env,分别是varEnv,和lexicalEnv,也就是变量环境(作用域)和词法环境

2.创建一个函数的作用域,并且varEnv和lexicalEnv都指向它

3.执行函数声明过程,创建并用函数调的参数值或undefined初始化var声明,并绑定到varEnv中

4.创建新的env作用lexicalEnv,其外部作用域为 varEnv,并且context的lexicalEnv指向他

5.将function绑定到varEnv中

 

 

3.执行有默认值的函数流程

function test(name = 'dog', showName = () =>{console.log(name)}) {
    var name = 'cat'
    showName()
}

test()

 

上面代码就是包含了默认值的情况,请先思考下上面的输出结果是什么?

答案是:dog

这个答案有点反直觉,因为在函数体里面,已经把name改为cat了,为什么还是默认值的dog呢?

我们在看看下面代码的运行结果就有点头绪了

function test(name = 'dog', showName = () =>{console.log(name)}) {
    var name = 'cat'
    showName() // dog
    console.log(name)// cat
}

test()

 

可以从上面代码的运行结果看出,showName 和 函数体里面访问的name不是一个变量

其原理在于:在es规范中提到,当函数的参数有初始化器的时候, 会创建一个单独的参数作用域,用于绑定参数的声明,所以我们会得到上面的运行结果

 

posted @ 2021-02-06 15:05  唐强136  阅读(49)  评论(0)    收藏  举报