我们知道javaScript不是一行一行的执行代码的 而是一段一段的,具体怎么分段的主要是下面的这个过程:
词法分析 -> 语法分析 -> 预编译 -> 解释执行
词法分析 词法分析是把字符流转换为记号流 将表达式转化为小的词法单元块
语法分析 将上一步的词法单元集合分析并最终转换为一个由元素逐级嵌套所组成的代表了程序语法结构的树,即抽象语法树(AST)
预编译 将AST转化为一段可执行代码;可执行代码分为三种:全局代码 函数代码 eval代码。
此时每块代码都会创建相应的执行环境(或称执行上下文) 同时j s创建了执行上下文栈(Execution context stack,ECS)来管理这些执行上下文。
解释执行 进入执行上下文,然后执行代码。
执行上下文有三个重要的属性:变量对象 ,作用域链, this 变量对象是与执行上下文相关的数据作用域,存储着上下文里面定义的变量和函数声明。
作用域链当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。
而且js的执行是严格按照作用域进行的 ,函数的调用的作用域早在书写的时候就确定了,不是在执行的时候确定的,这就是词法作用域(静态作用域)。
动态作用域:函数的作用域是在函数调用的时候才决定的。
举个例子:
var a = 123
function func (){
var a = 456
console.log(a)
}
func();
// 结果: 123; 因为func的作用域在定义时就创建了 在这个执行上下文中会向上找a的值,这时是静态作用域
var value = 'obj'
function xxx(){
function func(){
var value = 'arr'
return value
}
return func()
}
xxx();
// 结果: 输出 'arr' // 因为func的定义域在xxx内,会在这个作用域中找value的值 输出arr,这时是动态作用域,xxx调用的时候才确定func的作用域