当前位置:首页 > 日记 > 正文

对于Javascript 执行上下文的全面了解

对于Javascript 执行上下文的全面了解

在这篇文章中,将比较深入地阐述下执行上下文 – JavaScript中最基础也是最重要的一个概念。相信读完这篇文章后,你就会明白javascript引擎内部在执行代码以前到底做了些什么,为什么某些函数以及变量在没有被声明以前就可以被使用,以及它们的最终的值是怎样被定义的。

什么是执行上下文

Javascript中代码的运行环境分为以下三种:

全局级别的代码 – 这个是默认的代码运行环境,一旦代码被载入,引擎最先进入的就是这个环境。

函数级别的代码 – 当执行一个函数时,运行函数体中的代码。

Eval的代码 – 在Eval函数内运行的代码。

在网上可以找到很多阐述作用域的资源,为了使该文便于大家理解,我们可以将“执行上下文”看做当前代码的运行环境或者作用域。下面我们来看一个示例,其中包括了全局以及函数级别的执行上下文:

上图中,一共用4个执行上下文。紫色的代表全局的上下文;绿色代表person函数内的上下文;蓝色以及橙色代表person函数内的另外两个函数的上下文。注意,不管什么情况下,只存在一个全局的上下文,该上下文能被任何其它的上下文所访问到。也就是说,我们可以在person的上下文中访问到全局上下文中的sayHello变量,当然在函数firstName或者lastName中同样可以访问到该变量。

至于函数上下文的个数是没有任何限制的,每到调用执行一个函数时,引擎就会自动新建出一个函数上下文,换句话说,就是新建一个局部作用域,可以在该局部作用域中声明私有变量等,在外部的上下文中是无法直接访问到该局部作用域内的元素的。在上述例子的,内部的函数可以访问到外部上下文中的声明的变量,反之则行不通。那么,这到底是什么原因呢?引擎内部是如何处理的呢?

执行上下文堆栈

在浏览器中,javascript引擎的工作方式是单线程的。也就是说,某一时刻只有唯一的一个事件是被激活处理的,其它的事件被放入队列中,等待被处理。下面的示例图描述了这样的一个堆栈:

我们已经知道,当javascript代码文件被浏览器载入后,默认最先进入的是一个全局的执行上下文。当在全局上下文中调用执行一个函数时,程序流就进入该被调用函数内,此时引擎就会为该函数创建一个新的执行上下文,并且将其压入到执行上下文堆栈的顶部。浏览器总是执行当前在堆栈顶部的上下文,一旦执行完毕,该上下文就会从堆栈顶部被弹出,然后,进入其下的上下文执行代码。这样,堆栈中的上下文就会被依次执行并且弹出堆栈,直到回到全局的上下文。请看下面一个例子:

(function foo(i) {   if (i === 3) {    return;   }   else {    foo(++i);   }  }(0));

上述foo被声明后,通过()运算符强制直接运行了。函数代码就是调用了其自身3次,每次是局部变量i增加1。每次foo函数被自身调用时,就会有一个新的执行上下文被创建。每当一个上下文执行完毕,该上上下文就被弹出堆栈,回到上一个上下文,直到再次回到全局上下文。真个过程抽象如下图:

由此可见 ,对于执行上下文这个抽象的概念,可以归纳为以下几点:

单线程

同步执行

唯一的一个全局上下文

函数的执行上下文的个数没有限制

每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。

执行上下文的建立过程

我们现在已经知道,每当调用一个函数时,一个新的执行上下文就会被创建出来。然而,在javascript引擎内部,这个上下文的创建过程具体分为两个阶段:

建立阶段(发生在当调用一个函数时,但是在执行函数体内的具体代码以前)

建立变量,函数,arguments对象,参数

建立作用域链

确定this的值

代码执行阶段:

变量赋值,函数引用,执行其它代码

实际上,可以把执行上下文看做一个对象,其下包含了以上3个属性:

 (executionContextObj = {   variableObject: { /* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */ },   scopeChain: { /* variableObject 以及所有父执行上下文中的variableObject */ },   this: {}   }

建立阶段以及代码执行阶段的详细分析

确切地说,执行上下文对象(上述的executionContextObj)是在函数被调用时,但是在函数体被真正执行以前所创建的。函数被调用时,就是我上述所描述的两个阶段中的第一个阶段 – 建立阶段。这个时刻,引擎会检查函数中的参数,声明的变量以及内部函数,然后基于这些信息建立执行上下文对象(executionContextObj)。在这个阶段,variableObject对象,作用域链,以及this所指向的对象都会被确定。

上述第一个阶段的具体过程如下:

找到当前上下文中的调用函数的代码

在执行被调用的函数体中的代码以前,开始创建执行上下文

进入第一个阶段-建立阶段:

建立variableObject对象:

建立arguments对象,检查当前上下文中的参数,建立该对象下的属性以及属性值

检查当前上下文中的函数声明:

每找到一个函数声明,就在variableObject下面用函数名建立一个属性,属性值就是指向该函数在内存中的地址的一个引用

如果上述函数名已经存在于variableObject下,那么对应的属性值会被新的引用所覆盖。

初始化作用域链

确定上下文中this的指向对象

代码执行阶段:

执行函数体中的代码,一行一行地运行代码,给variableObject中的变量属性赋值。

下面来看个具体的代码示例:

 function foo(i) {   var a = 'hello';   var b = function privateB() {     };   function c() {     }  }    foo(22);

在调用foo(22)的时候,建立阶段如下:


  fooExecutionContext = {   variableObject: {    arguments: {     0: 22,     length: 1    },    i: 22,    c: pointer to function c()    a: undefined,    b: undefined   },   scopeChain: { ... },   this: { ... }  }

由此可见,在建立阶段,除了arguments,函数的声明,以及参数被赋予了具体的属性值,其它的变量属性默认的都是undefined。一旦上述建立阶段结束,引擎就会进入代码执行阶段,这个阶段完成后,上述执行上下文对象如下:

  fooExecutionContext = {   variableObject: {    arguments: {     0: 22,     length: 1    },    i: 22,    c: pointer to function c()    a: 'hello',    b: pointer to function privateB()   },   scopeChain: { ... },   this: { ... }  }

我们看到,只有在代码执行阶段,变量属性才会被赋予具体的值。

局部变量作用域提升的缘由

在网上一直看到这样的总结: 在函数中声明的变量以及函数,其作用域提升到函数顶部,换句话说,就是一进入函数体,就可以访问到其中声明的变量以及函数。这是对的,但是知道其中的缘由吗?相信你通过上述的解释应该也有所明白了。不过在这边再分析一下。

看下面一段代码:

 (function() {   console.log(typeof foo); // function pointer   console.log(typeof bar); // undefined     var foo = 'hello',    bar = function() {     return 'world';    };     function foo() {    return 'hello';   }    }());?

上述代码定义了一个匿名函数,并且通过()运算符强制理解执行。那么我们知道这个时候就会有个执行上下文被创建,我们看到例子中马上可以访问foo以及bar变量,并且通过typeof输出foo为一个函数引用,bar为undefined。

为什么我们可以在声明foo变量以前就可以访问到foo呢?

因为在上下文的建立阶段,先是处理arguments, 参数,接着是函数的声明,最后是变量的声明。那么,发现foo函数的声明后,就会在variableObject下面建立一个foo属性,其值是一个指向函数的引用。当处理变量声明的时候,发现有var foo的声明,但是variableObject已经具有了foo属性,所以直接跳过。当进入代码执行阶段的时候,就可以通过访问到foo属性了,因为它已经就存在,并且是一个函数引用。

为什么bar是undefined呢?

因为bar是变量的声明,在建立阶段的时候,被赋予的默认的值为undefined。由于它只要在代码执行阶段才会被赋予具体的值,所以,当调用typeof(bar)的时候输出的值为undefined。

好了,到此为止,相信你应该对执行上下文有所理解了,这个执行上下文的概念非常重要,务必好好搞懂之!

以上这篇对于Javascript 执行上下文的全面了解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

相关文章

powerpoint文字打字效果怎么设置

powerpoint文字打字效果怎么设置

设置,文字,步骤,效果,电脑软件,  打字效果,是增强汇报成果表现效果的一种形式,那么大家知道怎么设置打字效果呢?下面小编就教你怎么在ppt中设置打字效果吧,希望看完本教程的朋友都能学会并运用起来。ppt中设置打字效果的步骤选择“插入…

JS实现侧边栏鼠标经过弹出框+缓冲

JS实现侧边栏鼠标经过弹出框+缓冲

弹出框,侧边栏,鼠标,效果,电脑软件,可能这个标题起得不够恰当,简单来说就是:当鼠标移到最左侧时,移出一个框。 首先,我们用两个div来简单布局以下页面:<div id="box"> <div id="share">分享到</div></div>这个分享框的弹出原理是:把内层div定…

wps文字180度倒转的设置方法

wps文字180度倒转的设置方法

方法,文字,设置,电脑软件,wps,  我们知道图片可以进行旋转,那么文字可以进行旋转吗?我们编辑文档想要文字倾斜显示应该怎样做呢?下面给大家分享wps设置文字倒转的方法。wps文字180度倒转的设置方法wps文字180度倒转的设置步骤1:首先我们写下…

angularjs下拉框空白的解决办法

angularjs下拉框空白的解决办法

下拉框,解决办法,空白,电脑软件,angularjs,搜索angularjs下拉框空白,可以出现很多解决方案,但是对于静态字段来说,网上目前还没有找到解决方案,如下:<select class="form-control" ng-model="UserState" ng-init="UserState=0"> <option …

excel中count if 函数的使用方法ex

excel中count if 函数的使用方法ex

函数,使用方法,电脑软件,count,excel,  Excel IF函数即count if 函数,运用它可以对一系列繁杂的数据进行筛选,得到自己想要的数据结果。今天,小编就教大家在Excel中count if 函数的使用方法。Excel中COUNTIF函数使用方法一(1) 求真空单元格…

微信小程序 数据遍历的实现

微信小程序 数据遍历的实现

遍历,数据,程序,电脑软件,微信小,制作数据遍历的步骤在index.js中加入数据。在index.wxml中读取数据。wx:for-item可以指定数组当前元素的变量名wx:for-index可以指定数组当前下标的变量名这两个项也可以不指定,默认数组的当前项的下标变量…

JS实现课堂随机点名和顺序点名

JS实现课堂随机点名和顺序点名

顺序,课堂,电脑软件,JS,1. 效果:2. Html代码:<body><form> <div align="center"> <input type="button" value="开始点名" onclick="students()" class="ks"/> <input type="button" value="停止点名" onclick="stop()…

PPT文本框如何设置框线的颜色

PPT文本框如何设置框线的颜色

文本框,设置,颜色,如何设置,电脑软件,  在ppt的工作中,要设置文本框的框线颜色,可能有些朋友还不知PPT文本框怎么设置框线的颜色。以下是小编为您带来的关于PPT文本框设置框线的颜色,希望对您有所帮助。PPT文本框设置框线的颜色1、打开PPT,进…

2017版qq申请qq号步骤怎么注册申请

2017版qq申请qq号步骤怎么注册申请

步骤,账号,注册,手机验证,电脑软件,  对于qq新手来说,怎么申请qq号是他们首先想知道的问题,那么如何注册申请QQ账号呢?下面是小编为大家精心整理的注册申请QQ账号的方法,仅供参考。2017版qq申请qq号步骤百度搜索《腾讯客服》点击下面带有官方…

Excel中进行表格内文字换行的操作

Excel中进行表格内文字换行的操作

文字,换行,操作方法,表格,操作步骤,  生活中不管是学习还是工作都会用到excel表格,在表格栏有时候字太长会有无法显示完全或者显示太过的情况,、今天,小编就教大家在Excel中进行表格内文字换行的操作方法。Excel中进行表格内文字换行的操作…

PS的替换颜色和色彩范围选取的方法

PS的替换颜色和色彩范围选取的方法

选取,替换,方法,色彩范围,颜色,  颜色调整命令都是我们需要经常用到的功能,今天小编带新手们了解一下这个颜色调整命令的用处是怎么样的!PS的替换颜色和色彩范围选取的方法这个颜色调整命令和色相/饱和度命令的作用是类似的,可以说它其实就…

在Excel 2007中怎样筛选出需要的表

在Excel 2007中怎样筛选出需要的表

表数据,筛选,电脑软件,Excel,  Excel的强大相信大家都是有所感受的,它可以一次存放很多数据,但有时我们只想看到其中的一部分,那么我们应该怎么把这些数据筛选出来呢?以下是小编为您带来的关于在Excel 2007中筛选出自己需要的表数据,希望对您…