再次深入执行上下文 全局上下文 预定义的对象,可以访问其他所有预定义的对象、函数和属性。在顶层JS中,可以用关键字this引用全局对象(Window对象)。全局对象是由Object构造函数实例化的一个对象。全局上下文中的变量对象(VO)就是全局对象。 ### 函数上下文 AO(activation object,AO)变量对象,变量对象(VO)与活动对象其实是一个东西,当进入到一个执行上下文中,这个上下文的变量对象被激活,所以叫做活动对象,只有活动对象才能被访问。活动对象在进入上下文中通过arguments属性初始化。 ### 执行上下文 执行代码前变量对象包括: 1.函数的所有形参 由名称和对应值组成的一个变量对象的属性被创建 没有实参,属性值设为undefined 2.函数声明 由名称和对应值(函数对象)组成一个变量对象的属性被创建 如果变量对象已经存在相同名称的属性,则完全替换这个属性 3.变量声明 由名称和对应值(undefined)组成一个变量对象的属性被创建 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性 代码执行时会顺序执行代码,根据代码修改变量对象的值 ### 小结 1.全局上下文的变量对象初始化是全局对象 2.函数上下文的对象初始化只包括Arguments对象 3.在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值 4.在代码执行阶段,会再次修改变量对象的属性值 再次深入作用域链 查找变量时,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象,由多个上下文的变量对象构成的链表就叫做作用域链 ### 函数创建 函数的作用域在函数定义的时候就决定了。函数创建时会保存所有父级变量对象到其中,可以理解[[scope]]就是所有父变量对象的层级链,但不代表完整的作用域链。 ### 函数激活 函数激活时,创建VO/AO后,会将活动对象添加到作用链的前端。 Scope为执行上下文的作用域链。 ### 深入理解函数创建到执行 1.创建函数,保存作用域链到函数Scope 2.准备执行函数,创建函数执行上下文,将其压入执行上下文栈 3.函数不立即执行,复制函数Scope创建作用域链 4.用arguments创建AO,然后初始化,加入形参、函数声明、变量声明 5.将AO压入函数作用域链顶端 6.执行函数,修改AO的属性值 7.查找到AO值,函数执行完毕后,函数上下文从执行上下文栈中弹出 针对闭包基础的理解和使用 什么是闭包 闭包允许函数访问并操作函数外部的变量。只要变量或函数存在于声明函数时的作用域内,闭包即可使函数能够访问这些变量或函数。 调用一个函数时,会为这个函数调用创建一个执行上下文,并创建一个作用域链。然后用arguments和其他命名参数来初始化这个函数的活动对象(AO)。外部函数的活动对象是内部函数作用域链上的第二个对象。这个作用域一直向外反串起了所有包含函数的活动对象,直到全局执行上下文才终止。
闭包使用例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Ninja () { var feints = 0; this.getFeints = function (){ return feints; }; this.feint = function (){ feints++; }; } var ninja1 = new Ninja(); //赋值一个实例 ninja1.feint(); //undefined 通过实例无法直接获取该变量值,但是能调用方法去改变变量值 assert(ninja1.feints === undefined, "And the private data is inaccessible to us." ); assert(ninja1.getFeints() === 1,// 通过作用域内的方法获取私有变量的值,但是无法对该值进行直接操作 "We're able to access the internal feint count." ) var ninja2 = new Ninja();//新的实例有自己的私有变量 assert(ninja2.getFeints() === 0, "The second ninja object gets it’s own feints variable." );
闭包的特性 1 2 3 4 类似于“气泡”效果,每个实例都有一个单独的闭包,不能访问其他闭包中的变量,作用域(scopes)强相关。 关于执行上下文栈:上下文在变化。每次执行新的函数,都将创建新的函数上下文。内部代码结构可以访问外部代码结构中定义的变量。 查找变量是从内往外根据环境来查找数据,直到外层环境global还未找到则返回错误。 词法环境:块级环境,函数环境,全局环境
JS执行 1 2 3 4 5 JS引擎会访问并注册在当前词法环境中所声明的变量和函数。JS在第一阶段完成后开始执行第二阶段,具体执行取决于变量的类型(let ,const,var,函数声明)以及环境类型(↑词法环境)。 var myFunExper = funtion (){};//指向语数表达式(无法在声明前访问函数) var myArrow = (x) => x;//指向箭头表达式(无法在声明前访问函数) function fun (){}//作为函数声明进行定义(可以在声明前访问函数)变量提升!!
闭包小结 1 2 3 4 5 闭包的高级功能:通过构造函数内的变量以及构造方法来模拟对象的私有属性;处理回调函数,简化代码。 上下文栈的创建,推入,退出。 JS引擎通过词法环境跟踪标识符(词法环境:俗称作用域)。 var 定义距离最近的函数级变量或全局变量 let 和const定义距离最近级别的变量,包括块级变量。