javascript代码怎么执行,js流程引擎
这篇文章带给你一些关于javascript的知识,包括js引擎如何执行js代码。js引擎在执行js代码的时候,还会做词法分析、语法分析、语义分析等。自顶向下,并在代码分析后生成AST。希望对你有帮助。
推荐:javascript教程
我们经常可以听到关于执行环境、范围、原型(链)、执行上下文等等。他们都在描述什么?
JS代码的运行
我们知道js是弱类型语言,变量类型是在运行时确定的。js引擎在执行js代码时,也会处理词法分析、语法分析、语义分析等。自顶向下,并在代码解析后生成AST(抽象语法树),最后根据AST生成CPU可执行的机器码并执行。
另外,JS引擎在执行代码时会做其他处理,比如V8中有两个阶段:
编译阶段:这个阶段会创建执行上下文,包括创建变量对象(VO)(此时会初始化为未定义),建立作用域链,确定这个点。各自进入不同的操作环境。V8将创建一个新的执行上下文。执行阶段:在编译阶段创建的执行上下文被推入调用堆栈,成为正在运行的执行上下文。代码执行后,它会从调用堆栈中弹出。(下面是一个VO-AO的过程:JavaScript给变量赋值时,变量被使用,然后变量对象就会变成活动对象,转换后的活动对象就可以被访问了。)这就引出了两个概念:“执行上下文”和“作用域链”。
JavaScript执行上下文
从上面我们可以知道,当js代码执行一个可执行代码时,会创建相应的执行上下文。
首先,js中有一个与可执行代码相对应的概念:“执行环境”——全局环境、函数环境和eval。
其次,对于每个执行上下文,有三个重要的属性:
对象(即“VO”)范围链我们来看两段代码:
var scope=“全局范围”;函数checkscope(){
var scope=“本地范围”;
函数f(){
返回范围;
}
返回f();} check scope();var scope=“全局范围”;函数checkscope(){
var scope=“本地范围”;
函数f(){
返回范围;
}
返回f;} check scope()();他们会印什么?
为什么?答案是他们的执行上下文栈不一样!
首先,让我们定义一个堆栈
EStack=[global context];然后模拟第一段代码:
estack . push(check scope function context);estack . push(f function context);estack . pop();estack . pop();第二个代码是这样的:
estack . push(check scope function context);estack . pop();estack . push(f function context);estack . pop();原因是你可能需要先研究一下“封闭”这个概念!
JavaScript作用域和作用域链
首先,作用域是指程序中定义变量的区域。作用域指定如何查找变量,即确定当前执行的代码对变量的访问权限。
有两种范围:静态作用域和动态作用域。
JS采用的静态作用域也叫“词法作用域”。函数的作用域是在定义函数时确定的。
词法作用域中的变量会在编译过程中产生一个确定的作用域。这个范围就是“当前执行上下文”。在ES5之后,我们用“词法环境”代替作用域来描述执行上下文。词汇环境由两个成员组成:
自词法环境记录:用于记录自词法环境中的变量和对象;外部词汇环境引用:用于记录外部词汇环境中存在的引用;我们还是来看一个例子:
var值=1;函数foo(){
console.log(值);}功能栏(){
var值=2;
foo();} bar();回头看看上面的定义,应该打印什么?
我们来分析一下执行过程:
在执行foo()函数时,首先要弄清楚foo函数内部是否存在局部变量值。如果不是,就根据定义时的位置,查找上面一层的代码,即value=1。因此结果将打印为1。
当然,这不是那么简单就能概括的。可以从执行上下文的角度来分析。
建立作用域链
上面我们讲了词法环境的两个组成部分(作用域)。结合执行上下文不难发现,通过对外部词法环境的引用,可以沿着栈逐层扩展范围,建立起从当前环境延伸的链式结构。
我们再举一个例子:
函数foo(){
console . dir(bar);
var a=1;
功能栏(){
a=2;
} } console . dir(foo);foo();从静态范围来看,全局函数foo为自己的对象创建了一个[[scope]]属性。
foo[[scope]]=[global context];当我们执行foo()时,会进入foo函数的定义期和执行期。在foo函数定义期间,函数栏的[[scope]]会包含全局内置范围和foo的内置范围。
bar[[scope]]=[fooContext,global context];这就证明了这一点:“JS会通过外部的词法环境引用来创建变量对象的作用域链,从而保证对执行环境有权访问的变量和函数的有序访问。”
让我们回头看看执行上下文中的问题。前面我们讲过两者的区别。下面是为什么他们都把“局部作用域”打印成同一句话:“JS采用词法作用域,函数的作用域取决于函数创建的位置。”3354JS函数是用作用域链执行的,这个作用域链是在定义函数时创建的。在这个作用域链中定义了嵌套函数f(),其中变量scope必须引用一个局部变量。无论f()在何时何地执行,当f()执行时,这个绑定仍然有效。
基于作用域链的变量查询
当在自身的词法环境记录中找不到变量时,可以根据外部词法环境引用搜索到外层,直到最外层词法环境中的外部词法环境引用为空。
与此类似的还有“基于对象中原型链的搜索”:
Prototype:每个JS对象(除了null)在创建时都会与另一个对象相关联。这个物体就是我们所说的原型。每个对象都从原型“继承”它的属性。当读取实例的属性时,如果找不到,它将在与对象关联的原型中查找属性。如果找不到,它就会寻找原型的原型。直到顶级(__proto__为null)它们的区别才明显:原型链是通过原型属性建立对象继承的纽带;作用域链指的是内部函数可以访问外部函数的闭包。不管是直接的还是间接的,所有功能的范围链最终都与全局环境相联系。
推荐:javascript学习教程以上是JavaScript引擎如何执行JS代码的详细内容。更多请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。