唯心主义蠢货的[js知识总结] 执行上下文(VO,AO)和闭包

执行上下文(VO,AO)和闭包

执行上下文 Excution Context

概念

当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。

然后,使用 arguments 和其他命名参数的值来初始化函数的活动对象(activation object)。但在作用域

链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,

……直至作 为作用域链终点的全局执行环境。 ——《JavaScript高级程序设计》

每当可执行代码编译时时,就会进入执行上下文,即当前代码的执行环境,会形成一个作用域,分为:

  • 全局环境
  • 函数环境

按照函数调用栈的方式,压入弹出执行函数

生命周期

首先明白两个概念 VO(变量对象) / AO(激活对象)

变量对象(Variable object)是说JS的执行上下文中都有个对象用来存放执行上下文中可被访问但是不能被delete的函数标示符、形参、变量声明等。它们会被挂在这个对象上,对象的属性对应它们的名字对象属性的值对应它们的值但这个对象是规范上或者说是引擎实现上的不可在JS环境中访问到活动对象

激活对象(Activation object)有了变量对象存每个上下文中的东西,但是它什么时候能被访问到呢?就是每进入一个执行上下文时,这个执行上下文儿中的变量对象就被激活,也就是该上下文中的函数标示符、形参、变量声明等就可以被访问到了

EC(执行上下文)创建阶段

在这里插入图片描述

  • 创建作用域链(Scope Chain) (从当前函数到window的一条单链,通过这条链查找对象)
  • 创建变量(VO),函数和参数 (由上一篇文章可知变量提升)
  • 确定this的指向 (指向调用这个函数的对象)
EC(执行上下文)执行阶段

在这里插入图片描述

  • 初始化变量(AO)的值和函数的引用,解释/执行代码。

执行上下文和词法环境的区别

  • 1.性质不同,词法环境是一种规范,规定了这样标识符对应的作用域,执行上下文是代码执行顺序的确定
  • 2.用途不同,词法环境确定某个标识符(变量or函数)所在的作用域,执行上下文创建时,相应变量创建作用域链,执行时根据作用域链执行当前行代码
  • 3.作用对象不同,词法环境只是针对于某个标识符,执行上下文是针对整个代码的

闭包

概念

闭包是指有权访问另一个函数作用域中的变量的函数. —— 《JavaScript高级程序设计》

理解

当 闭包执行函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中;直到匿名函数被销毁后,闭包执行函数的活动对象才会被销毁

闭包函数执行环境的作用域链被销毁(Scope Chain is destoryed),但是由于当前活动对象被外部的一个变量x=AO(闭包)所获取,所以活动对象不会被销毁,即上下文执行环境不存在了,但是属性和方法还在。

闭包与变量

由于闭包保存的是活动对象,因此闭包只能取得包含函数中任何变量的最后一个值,由下例子可知

function createFunctions(){ 
 var result = new Array(); 
 for (var i=0; i < 10; i++){ 
 result[i] = function(){ 
 return i; 
 }; 
 } 
 return result; 
 //因为闭包一直不被调用 所以储存的是VO,当执行结束储存的是AO,然后所以的函数又指向i,所以i = 10
}
var x = createFunctions();
for(let i = 0 ;i < x.length;i++){console.log(x[i]())}
//返回为全10的数组

但是可以通过创建匿名函数的方式,强制更改result中i的指向,让闭包符合预期

function createFunctions(){ 
 var result = new Array(); 
 for (var i=0; i < 10; i++){ 
 result[i] = function(num){ 
 return function(){ 
 return num; 
 }; 
 }(i); // 此时i存入function的变量对象中 
 } 
 return result; 
}
var x = createFunctions();
for(let i = 0 ;i < x.length;i++){console.log(x[i]())}

闭包的this对象

详解

匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window(非严格状态下)——《JavaScript高级程序设计》

如下例子:

var name = "The Window"; 
var object = { 
 name : "My Object", 
 getNameFunc : function(){ 
 return function(){ 
 return this.name; 
 }; 
 } 
}; 
alert(object.getNameFunc()()); //"The Window"(在非严格模式下)

解释:每个函数在被调用时都会自动取得两个特殊变量:this 和 arguments。内部函数(匿名)在搜索这两个变量时,只会搜索到其活动对象(return的function的AO)为止,因此永远不可能直接访问外部函数中的这两个变量

但是可以通过闭包的方式将this对象放在返回的函数里,即可获得调用getNameFunc的对象object

var name = "The Window"; 
var object = { 
 name : "My Object", 
 getNameFunc : function(){ 
 var that = this; // 这个指向调用当前函数的对象,即object 
 return function(){ 
 return that.name;  // getNameFunc构成闭包,that.name保存this指向
 }; 
 } 
}; 
alert(object.getNameFunc()()); //"My Object"
发现的问题

function嵌套function 无法指定内层的function的this为外层function

function min(){
        var m = 1234;
        function sla(){
            return m;
        }
        return sla;
    }
 min()(); // 1234
 
当确定that指向时 
function min(){
        var m = 1234;
        function sla(){
            var that = this;
            return that.m;
        }
        return sla;
    }
 min()(); // undefined

后证实得

  • 如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。
  • **如果函数独立调用,那么该函数内部的this,则指向undefined,又因为非严格状态下this指向window,所以window.m为undefined **

参考

  • https://www.jianshu.com/p/9b984874776c
  • https://blog.csdn.net/w_q_1025/article/details/70145260
  • 知乎
  • 《JavaScript高级程序设计》
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值