javascript数据、变量类型与预解析
javascript数据类型与变量类型如下图:
执行上下文(Execution Context)
每当控制器转到可执行代码的时候,就会进入一个执行上下文,执行上下文可以理解为当前代码的执行环境,他会形成一个作用贵。javascript中的运行环境大概包括三种:
- 全局环境:js代码运行起来首先会进入该环境。
- 函数环境:当函数被调用执行时,会进入当前函数中的执行代码。
- eval(不建议使用,可忽略)
- 因此在一个javascript程序中,必定会产生多个执行上下文,js引擎会以栈的方式处理他们,这个栈我们称其为调用栈
(call stack)
。栈底永远是全局上下文(Global Context)
,而栈顶就是当前执行的上下文。在代码执行过程中,遇到上面3中情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。全局上下文会在浏览器窗口关闭后出栈。 - 关于上下文的总结:
- 单线程
- 同步执行,只有栈顶的上下文处于执行中,其他上下文需要等待
- 全局上下文只有唯一的一个,它在浏览器关闭时出栈
- 函数的执行上下文的个数没有限制
- 每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。
变量和函数在内存中的展示
- 基本数据类型是直接存在栈内存中,而引用类型是在栈中存储了指针,该指针指向了堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。基本数据类型按照值来访问,引用数据类型按照引用来访问。
预解析(也称声明提升):
- 在ES6之前,变量使用
var
声明,会存在变量的预解析,函数也有预解析。所谓预解析,就是在当前作用域中,javascript代码执行之前,浏览器首先会默认的把所有带var
和function
声明的变量进行提前声明或者定义。 - 声明和定义
1 | var num = 1; |
var声明的变量和function声明的函数在预解析的区别
var
声明的变量和function声明的函数在预解析的时候有区别,var
声明的变量在预解析的时候只是提前的声明,function
声明的函数在预解析的时候会提前声明并且会同时定义。也就是说var声明的变量和function声明的函数的区别是在声明的同时有没同时进行定义。下面举个例子:1
2
3
4
5
6
7
8console.log(num); //undefined
console.log(test); //test函数体,而不是undefined
var num = 1;
function test() {
console.log('test');
}
console.log(num); //1
console.log(test); //test函数体,没有返回值,所以会在输出一个undefined- 变量对象的创建过程为:先创建
arguments
对象,然后检查function
函数声明创建属性,最后检查var
变量声明创建属性。因此function声明会比var声明优先级更高一点,下面举个例子:
1
2
3
4
5console.log(num); //打印出了function num 而不是undefined。
var num = 1;
function num() {
console.log('test');
}
预解析的顺序
- 程序开始先预解析语法,标点符号是否有误,解析内存是否可容纳,解析变量……直到解析无误了,才开始按正常的流程顺序走。如果没有预解析顺序,直接按流程顺序走,可能程序执行到最后一个函数,发现了语法错误,才开始报错,那性能要有多差啊!
- 顺序内容:
- 文件内引用的
<script>
块依次解析,从上到下连成一片。 - 每个
<script>
块内的function
,var
解析到本块的开头。(先解析function
,再解析var
) - 依次解析每个环境,将
function,var
解析到环境的开头。
- 变量对象的创建过程为:先创建