JavaScript 解释上下文环境

Javascript中除了原型链,还有一重要知识环节 —— 上下文环境;通过对执行上下文环境的了解,能够让我们对Javascript内部原理有更深入的理解。

先以执行栈为引入,让大家感受一下:某个xxx.js代码在执行时,执行栈是怎么运作的,执行栈和上下文环境有什么关系?
执行栈: 一种数据结构栈;在js代码被执行时,已被创建的执行上下文按照被创建的顺序依次被存储(压入)栈中。
【图一】
在这里插入图片描述
【图二】
在这里插入图片描述
依照上面图一、图二为例子,解释下执行栈的执行过程:
Js引擎执行到代码文件js-test.js时,会创建全局执行上下文(Global Excution Context)并压入栈中。对应图二中第1幅图的Global Excution Context被压入栈;

当执行到图一第14行代码时,即执行到函数method_1th,会创建新的函数执行上下文并压入栈中。对应图二中第2幅图的method_1th函数上下文环境(function method_1th() Excution Context)被压入栈。

在执行函数method_1th时,执行到第6行代码method_2th时,会创建当前函数的函数执行上下文并压入栈中。对应图二中第3幅图的method_2th函数上下文环境(function method_2th() Excution Context)被压入栈。

当执行到第7行代码,函数method_2th已执行结束。则执行栈中顶层的method_2th函数上下文被弹出,此时执行控制流程从method_2th函数上下文环境切换到method_1th函数上下文环境。对应图二的第4幅图!

然后,函数method_1th执行结束,即执行到第15行代码时,执行栈中顶层的method_1th函数上下文被弹出,此时执行控制流程从method_1th函数上下文环境切换到Global Excution Context全局执行上下文环境。

由此可见,Javascript中的全局执行上下文和函数执行上下文都是由Js引擎所创建。并且是在Js引擎执行过程中依次创建,而盛放这些上下文的数据结构叫执行栈。

好比Java语言中的Java虚拟机栈,每个方法被执行的同时,都会创建一个栈帧(Stack Frame)。而每一个方法从调用直到执行完成的过程,则对应着一个栈帧在虚拟机栈从入栈到出栈的过程!

下面则是执行上下文的分类:
在这里插入图片描述

下面则是创建执行上下文的过程:
在这里插入图片描述
结合上图的思维导图,通过代码环境逐个分析他们的创建过程:
关于 this 的绑定
在这里插入图片描述
从执行栈的执行上来解释,在执行第9行代码那一刻之前,全局上下文环境已经创建且被压入了执行栈,此时环境中的this指向全局对象。

当在第9行代码执行时,myFunction函数上下文被创建并压入执行栈中(partialFunc函数定义在了myFunction函数中,不会被执行)且处于栈顶层,此时执行控制流程处在myFunction函数上下文环境中。此时函数partialFunc中的this指向myFunctioin(结合创建执行上下文的过程图可知,this的指向取决于函数是怎么被调用的)。

当执行到第15行代码时,新的函数执行上下文被创建并压入栈中,即partialFunc函数执行上下文。此时执行控制流程处在partialFunc函数上下文环境中。由于this的指向取决于函数是怎么被调用的,而当前函数的执行没有指定任何引用对象,所以当前函数上下文环境的this指向全局对象。

通过对this绑定的分析之后,生出这个疑问:
常用方法call() 和 apply() 中的 this 是绑定到什么对象上?
方法call() 和 apply() 被调用时,即被调用的方式是 this.方法名.call(参数1, 参数2) this.方法名.apply(参数1, 参数2)

如果不关注.call() 和 .apply(),结合关于 this 的绑定进行分析。可以得出结论,此时的方法内部的this指向的是调用方法 (this.方法名)this

但是,如果方法call() 和 apply() 使用调用方式 —— this.方法名.call(参数1, 参数2) this.方法名.apply(参数1, 参数2) ,那么旨在使用参数1来更改this(参数1来替换this),具体解释可见下方代码:
在这里插入图片描述
bind() 方法中的 this
ECMAScript 5 引入了 Function.prototype.bind。调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,this 将永久地被绑定到了 bind 的第一个参数,无论这个函数是如何被调用的。
因此bind方法在使用上和call、apply是一致的。只是bind是会新建一个新的函数!

关于词法组件的创建
词法组件的创建,这里分为在两种条件环境下:1全局上下文环境; 2函数上下文环境;创建之后的结构如下图:

在这里插入图片描述
由于变量环境和词法环境相似,因此与词法环境的环境结构式一致的。
下面通过变量环境细致的了解下在上图框架结构下的变量环境是如何的!~
关于变量环境组件的创建
在这里插入图片描述
结合上图代码,分析:
该变量环境组件的创建过程从代码上来看,该js代码文件中包含了两类上下文环境 —— 因此需要创建全局上下文和函数上下文。
创建全局上下文环境
在这里插入图片描述
在全局上下文环境中 this的绑定指向全局对象;使用let、const修饰的变量a和b,以及函数multiply在词法环境中被定义且未被初始化(uninitialized)
而使用var修饰的变量c,在变量环境中被定义且已被初始化(undefined)

创建函数上下文环境
在这里插入图片描述
从源代码文件的第10行代码 c = multiply(20, 30); 来看,函数上下文环境中this指向的也是全局对象。而在词法环境中使用var修饰的变量g在变量环境中被定义且已被初始化(undefined)。函数上下文环境中的词法环境中,被定义的变量则是函数的参数。

参考文章:
https://juejin.im/post/5b
https://juejin.im/post/585

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值