JS的引擎
众所周知,任何一门语言都会有专门的执行器来执行,JS也不例外。JS的执行环境有两个,分别是浏览器和node。 嗯? 这个时候就会有些小伙伴有疑问了:为什么这两个东西都可以执行呢? 因为这两个执行环境都有--V8引擎。
V8引擎
-
what is that ?
V8 引擎的本质就是是一段庞大的函数,它可以读懂 JS 并执行
给大家举个简单的例子
console.log(a); var a = 1如果咱们要跑这段代码,按照常理是不是得报错?
好,那咱们用 node 跑一下就知道了,结果居然是 undefined , 而不是想象中的红色字体
这个时候不得不谈到 JS 的执行顺序了
JS 的执行
- 代码被 V8 读取到的第一时间, 并不是执行,而是会先编译(梳理)
- 梳理
- 分词/词法分析
- 解析/语法分析 -- AST(抽象语法树) 获取有效标识符 在该例子中有效标识符为
- 生成代码
因此,在 V8 眼里代码长成这个样子
var a console.log(a); a = 1作用域
分类
- 全局作用域(整份份代码被称为全局作用域)
- 函数作用域(参数也是该作用域的一个有效标识)
- 块级作用域 ( const , let 和 {} 语法配合使用会导致声明的变量处在一个作用域中)
作用机制
由内向外(就近原则,找到了就不找了),不能由外向内找 举个例子 那现在我们的小伙伴可以先思考一下,把你的手指停在这里,思考一下现在输出的a会是多少呢?
从上往下V8引擎执行,到最下面。函数调用的时候,函数才执行,函数执行的时候,我在函数作用域里它就已经找到了a的值,所以输出的a就是20了
例子2 好,下面这个例子大家先思考一下它的值是多少呢?思考一下,随后sigma老师再给大家揭晓答案。
与上一个例子同理V8引擎从上执行到下面,它并没有调用函数。而是在调用函数之前就已经把a的值给输出了,那么这个时候的a它在哪里呢?显而易见。全局作用域,所以这个时候a输出的值就是10。 为了让大家更好的理解,Sigma老师专门把全局作用域和函数作用域给标注出来了,加上自己的理解小伙伴们好好的捋一下哟。
Sigma老师相信小伙伴们掌握的不错,那么大家可以挑战一下下面这个题目哦
那么此时a输出的值是什么呢? a的值是20吗?咱们拿node跑一下就知道了,报错! 看到报错,咱们不要灰心,咱们要看一下报错的内容是什么.
找到了a is not defined. a尽然没有被定义! 诶?不对劲啊,怎么会出现这种情况呢?假装咱们是V8引擎,咱们来跑一下,前面第三行到第五行不执行,因为函数没有调用,第六行函数被调用了,然后我们再去函数里面找,找到了a被定义并且被赋值成20,然后咱们走到第七行输出a,但是a竟然是没有被定义!说明什么?说明在全局作用域里面没有一个a被定义,但是函数作用域里面a被定义了,并且被赋值了。相信咱们聪明的小伙伴就已经想到了,在js这门语言中作用域是不是有一个特殊的性质呢?没错,在这个例子中全局作用域不能访问到函数作用域。在js这门语言中有一条这样的铁律,外层作用域不能向内层作用域,作用域只能由内往外查找。
既然知道这条规则,那我们来尝试假装自己是V8引擎跑一下下面这段代码。
首先全局定义了一个a为10,其次,全局定了一个foo函数,然后全局调用了foo函数,foo函数定义了一个a为20,foo函数里面还定义一个函数为bar函数,好,现在问题来了,那bar函数里面这个输出的a找的是谁呢?怎么找?首先找bar函数作用域有没有a?没有,那下一步找它的外层作用就是负函数里面。的作用域有没有a? a等于多少?20,所以找到了a之后就停止了,不会再到全局作用域里面去找。
Well,那么sigma老师再给大家介绍一个函数中 参数怎样和作用域联系在一起
这个时候输出的是什么呢?a我们已经知道了等于20,那么b呢?先从bar这个函数作用域里面找,找不到向外到foo这个函数作用域里面找,也找不到再向外找全局作用域去找,找到了等于2,所以输出的就是22啦。
块级作用域特点
区别是const不能修改值,let可以 只要和带 {} 的语法配合使用,自动形成作用域 有些小伙伴不相信能形成,那咱们跑一下
访问不到a,由此可见形成了块级作用域
此时用node去跑这个代码,结果是a is not defined.为什么呢?这个现象被称为--暂时性死区
当一个 {} 语句中存在let x时,在该 {} 中访问的x永远都只能访问 {} 内部的x,就算内部访问不到,也不能访问外部的x这种规则称为--- 暂时性死区
- 梳理