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.两种写法的函数实际存储方式大概是怎样的?
🤣一个于JS作用域的基础问题
从作者的提问可以了解到的是,作者对于JS作用域没有一个清晰的概念。下面先交代一下JS的作用域是什么吧!
作用域
Java Script引擎在执行JavaScript代码时,需要用到编译器、执行引擎和作用域。
动态作用域VS静态作用域
在编程语言中可以将作用域分为动态作用域和静态作用域
JS的作用域属于静态作用域,简单理解就是,作用域关系是在代码编写的时候就已经确定了的,无论在哪里调用和执行都不会变。
JS中的作用域
首先,在js中的作用域分为全局作用域、函数作用域和块级作用域。在之前js只存在全局作用域和函数作用域,ES6之后引入了块级作用域。而块级作用域只适用于
const
和let
声明的变量,所以这里我们不需要考虑块级作用域。在
js
中变量的查找是从当前的函数作用域开始向上查找的,也就是说如果在test
中使用变量a
,那么会先在test
的函数作用域查找,如果在test
中存在变量a
则停止查找。回答问题
问题一
这里涉及到了一个全局作用域和两个函数作用域,当执行
a()
时,函数a
中声明了函数mystart
,也就是说a
的函数作用域是mystart
的父级作用域。当执行
mystart
时,console.log(io)
会在当前的mystart
作用域中查找io
变量,发现mystart
中不存在io
变量后,会向mystart
的父级作用域(a
函数作用域)查找,此时在a
函数作用域中顺利找到io
变量。于是顺利打印出"io"
。但是对于下面的代码:
这段代码与上面的不同之处在于,
mystart
的父级作用域不再是函数a
,而是全局作用域。这时候在执行
mystart
时,查找io
变量就不会再去a
函数作用域中查找了,由于全局作用域中没有io
变量。那么console.log(io)
就会查找不到io
变量,那么抛出ReferenceError
异常。问题二
之所以有这样的疑惑,是因为错误的将JS的作用域机制理解成了动态作用域导致的。
然而JS采用的是静态作用域规则,也就是说JS的作用域是在编写代码时就确定的。将
mystart
写在全局作用域下,那么mystart
的父级作用域就是全局作用域,而不是mystart()
调用时所在的作用域(a
函数作用域)。所以题主理解错了JS的作用域,才会奇怪为什么不会去嵌套作用域中寻找!
问题三
参考这两个图