JS执行机制

189 阅读3分钟

由于JS是弱类型语言,所以在运行的时候才能确定变量,但是在运行之前都会JS代码都是先编译再执行, 编译后会生成执行上下文可执行的代码

调用栈call stack

用来管理函数调用关系的一种数据结构,先进后出,如果执行到当前函数,就把当前函数的执行上下文推入栈中,如果函数执行完毕,则推出销毁

20a832656434264db47c93e657e346a7.png

执行上下文

类型

  • 全局执行上下文,第一次载入JS代码的时候被创建,有且仅有一个全局执行上下文
  • 函数局部执行上下文,每次执行函数的时候都会创建

组成部分

  • 变量环境
  • 词法环境
  • outer-词法上外层执行上下文的指向
  • this-执行阶段所绑定的执行上下文

b398610fd8060b381d33afc9b86f988d.png

创建流程

  • 当遇到var,function等声明的变量或函数的时候,会把此类函数的变量添加到变量环境的变量对象上,等到后面执行阶段才会赋值-变量提升的原因
  • 当遇到let/const等ES6的块级作用域的时候,会把他们依次推入到词法环境中,词法环境内部有一个小型栈用于维护词法变量,栈的底部是最外层的变量,进入下一个块域就会把内部的变量推入到此栈的顶部,执行结束后推出
  • 根据词法判定指向outer
  • 根据执行情况绑定this

变量查找顺序

词法栈顶向下 => 变量环境 => 闭包(如果存在) => outer指向的外部执行环境 => 全局执行环境

作用域/作用域链

  • 变量和函数有权访问的范围,控制着他们的可见性和声明周期
  • 词法决定的,也就是在编写的时候就已经确定
  • 由于每个执行环境都有一个outer指向起词法决定的外部执行环境,所以基本词法嵌套的执行环境都可以通过outer链到全局执行环境,这个链路就叫做作用域链
  • 变量也是通过作用域链来查找的

闭包

  • 能够访问其他作用域中变量的函数叫闭包函数
  • 如果一个函数返回了内部函数,内部函数用到了此函数的变量,则这些变量就会变成一个闭包,被一直存在作用域链上,以便内部函数能够访问到

this

  • 简单来说为了能够使内部方法访问到内部属性,JS提出了this机制
  • 只有当函数被调用的时候才能确定this绑定的执行上下文
  • 每个执行上下文都有一个this

由于JS机制没有明确this的只想,所以根据函数调用的不同来判定this最终的绑定

  • 函数直接的调用,默认存在一个隐式绑定到全局,也就是window,其他宿主可能是undefined
  • 通过call/apply/bind来手动强制绑定this
  • 构造函数中的this指向的是构造函数最终的实例
  • 嵌套的函数中的this是不会继承的,最终还是看函数执行的绑定情况
  • 箭头函数不存在this,所以内部this用的是父级的this
  • setTtimout等回调this指向的是全局,如果是箭头函数,则需要根据词法分析决定