函数写在函数里面和函数外面有什么区别?

function a(){
    var io = "io"
    mystart()
    function mystart(){
        console.log(io);
    }
}
a()

function a(){
    var io = "io"
    mystart()
}
function mystart(){
    console.log(io);
}
a()

请教一下:
1.为什么第一个可行,第二个不可行?
2.为什么第二个访问io变量的时候不会按照访问规则当前函数作用域下访问不到,到嵌套着它的函数作用域中去寻找?
3.两种写法的函数实际存储方式大概是怎样的?

阅读 1k
3 个回答
✓ 已被采纳

🤣一个于JS作用域的基础问题

从作者的提问可以了解到的是,作者对于JS作用域没有一个清晰的概念。下面先交代一下JS的作用域是什么吧!

作用域

Java Script引擎在执行JavaScript代码时,需要用到编译器、执行引擎和作用域。

  • 编译器:语法分析、代码生成等功能。
  • 执行引擎:从头到尾负责整个程序的编译及执行过程。
  • 作用域:负责收集并维护所有标识符组成的一系列查询,并确定当前执行代码对这些标识符的访问权限。

动态作用域VS静态作用域

在编程语言中可以将作用域分为动态作用域静态作用域

  • 动态作用域:在运行时确定作用域关系
  • 静态作用域:在编译时确定作用域关系

JS的作用域属于静态作用域,简单理解就是,作用域关系是在代码编写的时候就已经确定了的,无论在哪里调用和执行都不会变。

JS中的作用域

首先,在js中的作用域分为全局作用域、函数作用域和块级作用域。在之前js只存在全局作用域和函数作用域,ES6之后引入了块级作用域。而块级作用域只适用于constlet声明的变量,所以这里我们不需要考虑块级作用域。

// 这里是全局作用域
function test() {
  // 这里是函数作用域
}

js中变量的查找是从当前的函数作用域开始向上查找的,也就是说如果在test中使用变量a,那么会先在test的函数作用域查找,如果在test中存在变量a则停止查找。

回答问题

问题一

为什么第一个可行,第二个不可行?
function a(){
    var io = "io"
    mystart()
    function mystart(){
        console.log(io);
    }
}
a()

这里涉及到了一个全局作用域和两个函数作用域,当执行a()时,函数a中声明了函数mystart,也就是说a的函数作用域是mystart的父级作用域。

image.png

当执行mystart时,console.log(io)会在当前的mystart作用域中查找io变量,发现mystart中不存在io变量后,会向mystart的父级作用域(a函数作用域)查找,此时在a函数作用域中顺利找到io变量。于是顺利打印出"io"

但是对于下面的代码:

function a(){
    var io = "io"
    mystart()
}
function mystart(){
    console.log(io);
}
a()

这段代码与上面的不同之处在于,mystart的父级作用域不再是函数a,而是全局作用域。

image.png

这时候在执行mystart时,查找io变量就不会再去a函数作用域中查找了,由于全局作用域中没有io变量。那么console.log(io)就会查找不到io变量,那么抛出ReferenceError异常。

问题二

为什么第二个访问io变量的时候不会按照访问规则当前函数作用域下访问不到,到嵌套着它的函数作用域中去寻找?

之所以有这样的疑惑,是因为错误的将JS的作用域机制理解成了动态作用域导致的。

然而JS采用的是静态作用域规则,也就是说JS的作用域是在编写代码时就确定的。将mystart写在全局作用域下,那么mystart的父级作用域就是全局作用域,而不是mystart()调用时所在的作用域(a函数作用域)。

所以题主理解错了JS的作用域,才会奇怪为什么不会去嵌套作用域中寻找!

问题三

两种写法的函数实际存储方式大概是怎样的?

参考这两个图

image.png

image.png

  1. 因为变量 io 的作用域的区别导致的。
  2. 因为第二个中函数 mystart 没有定义在 a 函数中,而是定义在了全局作用域中,所以第二中的 console.log(io) 不会找函数 a 中的 io 而是在全局作用域中找变量 io
  3. 第一种写法是 mystart 函数存储在 a 函数中,所以 console.log(io) 可以找到函数 a 作用域中的 io 变量,第二种写法是 mystarta 函数都定义在全局作用域中。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏