Function执行原理 & 闭包
Execution Context 执行期上下文
在java或c语言中,都有块级作用域这个概念,而js中则没有。
在js中,作用域只有一种,即函数级作用域。
而执行期上下文,可以理解为函数的作用域或执行环境。
在代码层面,执行期上下文是嵌套存在的
在js引擎内,执行期上下文是以栈的形式进行存放
栈的最底部存放的global上下文,每次执行一个函数,则会创建一个上下文放入栈中,执行结束后再pop移除。
(function foo(i) { if (i === 3) { return; } else { foo(++i); } }(0));
当前的执行环境则永远使用存放在栈顶的上下文对象。
参考博文:
- 深入理解Javascript之执行上下文(Execution Context) -- JavaScript -- IT技术博客大学习 -- 共学习 共进步!
- 深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇) - 汤姆大叔 - 博客园
Function 执行原理
js中有在function上面有很多的用法和概念,就比如作用域链,闭包这些。
其实问题归结到了根本,都在于Function在执行时做了什么。
这个是以下内容的一个思维导图:
以Function的生命周期划分,分为:创建阶段 和 执行阶段
这里从执行阶段开始,以 执行函数内部代码 为时间点分成3个阶段:
- 执行前
- 执行时
- 执行后
执行前
当执行一个函数时,会创建一个函数的执行环境,即执行期上下文对象(execution context)。
ExecutionContext = { VO:{ // Variable Object(全局上下文独有) // 变量 (var, 变量声明); // 函数声明 (FunctionDeclaration, 缩写为FD); }, AO:{ // Activation Object (函数上下文独有) // 变量 (var, 变量声明); // 函数声明 (FunctionDeclaration, 缩写为FD); // arguments }, scopeChain:{..}, this:{..} }
该对象主要做了三件事情:
-
确定函数内所有的变量 (AO | VO)
- AO:通过上下文栈中的当前上下文,获取参数,创建arguments对象
- AO & VO:扫描代码,创建所有函数声明(hoist作用域提升的原因,这些函数将进入创建阶段)和变量声明(值为undefined)
- 创建作用域链 (scopeChain = (AO | VO) + [[Scope]])
- 确定this指向 (由当前所处的执行期上下文提供)
VO & AO
VO 和 AO 的作用是存储函数中执行时需要用到的所有函数和变量。
执行期上下文分为两种:
- 全局上下文 (global,在上下文栈最底部,这个对象只存在一份,它的属性在程序中任何地方都可以访问)
- 函数上下文 (每次在函数调用时进行创建)
这两种上下文的区别就在于其创建方式和VO的访问性。
全局上下文的VO可以直接访问,VO对象指向的是global自身
var name = {}; name === this.name // true name === window.name // true
函数上下文的VO不能直接访问,创建活动对象AO来代替VO。
因此函数上下文只有AO,VO没有。
创建作用域
函数生命周期分为两个阶段:
- 创建阶段 (创建
[[scope]]
) - 执行阶段 (创建
scopeChain
)
在函数创建阶段,[[scope]]就已经被创建了。
function say(){ var words = "hello"; hello(); // 输出:hello function hello(){ console.log(words); } } say.[[scope]] = [ GlobalExecutionContext.VO ]
遵循 [[scope]] = superExecutionContext.scopeChain + superFn.[[scope]]
这个规则。
该变量[[scope]]
是一种静态变量,一直存在,直至函数被delete或垃圾回收。
进入执行阶段,执行期上下文初始化作用域链scopeChain。
say.ExecutionContext = { AO : { words : undefined, arguments : [...] }, scopeChain : say.[[scope]].concat(this.AO) }
即
say.ExecutionContext = { AO : { words : undefined, arguments : [...] }, scopeChain : [ say.ExecutionContext.AO, // 创建自身活动对象 GlobalExecutionContext.VO ] }
遵循 scopeChain = (AO | VO) + [[Scope]]
这个规则。
闭包也遵循这个规则,在say函数执行时,内部函数hello进入创建阶段。
hello.[[scope]] = [ say.scopeChain, GlobalExecutionContext.VO ]
在执行hello()
时,进入执行阶段
hello.ExecutionContext = { AO : { arguments : [...] }, scopeChain : [ hello.ExecutionContext.AO, say.scopeChain, GlobalExecutionContext.VO ] }
参考博文:
- js 中的活动对象 与 变量对象 什么区别? - JavaScript - 知乎
- 深入理解JavaScript系列(12):变量对象(Variable Object) - 汤姆大叔 - 博客园
- 深入理解JavaScript系列(14):作用域链(Scope Chain) - 汤姆大叔 - 博客园
确定this执向
this由该函数的执行环境所确定
function person = { say : function(){ console.log(this); } } person.say() // this指向person对象 var say = person.say; say() // this指向window
参考博文:
执行时
函数的内部代码执行时,由于在执行前将函数声明(function关键字)和变量声明(var关键字)全部创建到了AO中。
因此会存在一种hoist,即作用域提升的问题。
执行后
在函数的内部代码执行后,会销毁函数的执行期上下文。
与此同时AO也将被销毁,除非有引用的情况。
function say(){ var words = "hello"; hello(); // 输出:hello function hello(){ console.log(words); } return hello; // 将hello抛出 } var hello = hello.say();
此时的作用域情况如下
window.hello.[[scope]] = [ say.scopeChain : [ say.ExecutionContext.AO, GlobalExecutionContext.VO ] ]
由于 hello.[[scope]]
中留有 say.scopeChain
即 say.ExecutionContext.AO
的引用,所有不会被删除。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
程序员幽默:66条让你笑爆肚皮的程序员段子
1、程序猿最烦两件事,第一件事是别人要他给自己的代码写文档,第二件呢?是别人的程序没有留下文档。 2、程序猿的读书历程:x 语言入门 —> x 语言应用实践 —> x 语言高阶编程 —> x 语言的科学与艺术 —> 编程之美 —> 编程之道 —> 编程之禅—> 颈椎病康复指南。 3、还没上大学的时候,高三暑假,跑到家那边的图书城想买传说中的C++的书,然后看到一本C#,我一看,嘿,这个++还写得挺艺术的,重叠起来了,于是把C#买了回来…… 4、问:程序猿最讨厌康熙的哪个儿子。答:胤禩。因为他是八阿哥(bug) 5、有一天,程序猿们突然发现他们要涨的工资掉到井里啦!大家都很害怕,连忙一个吊着一个,从树上伸到井里去捞工资。正好他们摸到工资的时候,一个老程序员忽然兴奋的大叫:别蠢了,要涨的工资还好好的挂在天上呢! 6、诸葛亮是一个优秀的程序猿,每一个锦囊都是应对不同的case而编写的!但是优秀的程序猿也敌不过更优秀的bug!六出祈山,七进中原,鞠躬尽瘁,死而后已的诸葛亮只因为有一个错误的case-马谡,整个结构就被break了! 7、生活中程序猿的真...
- 下一篇
Leetcode打卡 | No.016 最接近的三数之和
写在前边:欢迎和小詹一起定期刷leetcode,每周一和周五更新一题,每一题都吃透,欢迎一题多解,寻找最优解!这个记录帖哪怕只有一个读者,小詹也会坚持刷下去的! No.16 最接近的三数之和 题目:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).题目分析:这一题,基本上数之和都有一大家子了。两数之和;三数之和;最接近的三数之和……相信上一题(三数之和)大家多少还有些印象,没有的自行去复习噢。上一题我们是首先进行排序,将数组进行从小到大的排序,之后固定一个数,在这个数之和,选择从两端进行向中间的逼近。这里思路如下:列表排序,sort()方法一层循环,固定一个数(索引记为 i),在这个数之后,记 l 指向第一个数,r 指向最后一个数如果nums[i]+nums[l]+nums[l+1]大于目...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8编译安装MySQL8.0.19
- CentOS关闭SELinux安全模块
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Redis,开启缓存,提高访问速度