zoukankan      html  css  js  c++  java
  • JS coding thinking

    概念:
    (1)执行上下文:
    活动在执行上下文组在逻辑上组成了一个堆栈。堆栈的底部永远是全局上下文(global context),而顶部是当前执行下文。而堆栈在EC的执行和退出的时候被修改。触发执行上下文的条件,是全局代码,函数代码,eval代码.并且是在代码运行时候!EC栈才会真正存在。
    
    执行上下文(EC)的组成:[sc]变量对象,[sc]作用域链, [this]。
    这里不考虑eval了。
    
    
    
    (2)变量对象:
    其实变量对象是一个虚拟的概念。在不同的上下文中对应着不同的实现。 全局情况:[vo = window] (a) window具有如下特征。 1)程序执行以前,就已经准备好了 2)单例 3)可以在任何位置访问 4)生命周期与页面寿命相同,关闭页面,window消失 函数中,或者说是实例以后的对象中,vo就是激活对象:[vo == AO 活动对象] (b) 激活对象 fun EC = { vo : Activation Object; } 而这个激活对象中包含了arguments这个属性。 arguments : { callee: length: [0]: [1]: ... [length-1]: } (3)变量实例化 时期:进入上下文的时候,代码执行以前。 变量实例化的含义就是:给VO做初始化, (a)---全局时候,VO代表windiw,这个时候给window绑定变量和函数; (b)---在函数中,对应的VO就是AO(激活对象),对应的就是[函数参数,声明式函数,变量]。 ----这里初始化,就是给arguments挂上上面的参数,变量=undefined,fun->function存储的代码段。 [注意:这个变量一定是var声名!!!如果一个如这种 aa = 100;是无法识别的!!!!] [注意:初始化的优先级是:声明式函数 》 函数参数 》 变量 ] 例子: 1) function test(x){ alert(x); var x = 20; } test(10); // 打印 10 证明函数形参》变量 2) function test(x){ alert(x); var x = 20; function x(){ } } test(10); // 打印函数 声明式函数 》 形参 3) function test(){ alert(x); var x = 20; } test(); // 打印undefined 是内部的变量x,但代码执行的时候,并没出被初始化为10。 (4) 代码执行过程---- 1) 进入上下文 --- 初始化this, 变量对象, 作用域链 --- 变量实例化 2) 代码执行 首先:这里有一个需要注意的地方 例子: var x = 10; window.y = 20; eval("var z = 30;"); delete window.x; delete window.y; delete window.z; alert(window.x); 10 alert(window.y); undefined alert(window.z); undefined 证明var定义的变量,挂在window下面是无法被删除的。而eval执行的和window.a 直接声明的,是可以卸载删除的。 (5) 作用域链: 首先是如何创建作用域链,用function创建。并且需要注意的是,一个函数的作用域创建的时候,从这里‘{’开始,到‘}’这里结束。作用域与函数是共存亡的。而如果函数内部,还有多个函数,那么从内侧向外层,就形成了作用域链。 全局上下文中的 scope chain = [当前对象] 函数上下文中的 scope chain = [当前激活对象, function.[[scope]] 这里 function.[[scope]] = 函数创建时所在的EC.scope chain. <script> fun A () { fun B() { ----> 这里声明B的scope时 =》 [A(ao), A.scope] // } B() ----> 执行的时候scope ----> [B(ao), A, window], 因为执行的时候,就会有B的活动对象(ao)了。 } </script> 作用域链的作用是去找寻变量和函数的,从内向外。其实就是从左向右遍历,进行变量和函数匹配。 this: 进入上下文之前确定,在运行时不可以改变。 记住: XXX(); this--> window xxx.XXX(); this-> xxx xxx[XXX](); a.b.c() this-> a.b , c()是a.b的属性。 举个例子: //获取对象构造函数名称 function getConstructorName(obj) { return obj && obj.constructor && obj.constructor.toString().match(/functions*([^(]*)/)[1]; } var test = {x: 10}; var temp = { x: 20, do: function (){ console.log(getConstructorName(this)); console.log(this.x); } }; temp.do(); //obejet[temp] 20 test.do = temp.do; test.do(); //obejet[test] 10 var foo = test.do; foo(); //window, undefined 注意:函数表达式,只有在代码执行到哪一行的时候,才会去创建它,是创建!!不是执行!!! 在创建的时候,是当前上下文的scope,没有执行,只是创建!!!scope就是当前上下文的scope。 只有在执行的时候,才会有自己的AO。 而在执行的时候,才开始创建它自己的AO。 -------------------------------------------------- var y = 10; function test(){ var y = 2; return function(x){ var a = 10; alert(y + x + a); } } var fun = test(); fun(10); ------------------------全局代码初始化--------------------------------------- 首先创建全局的上下文。 EC = [ vo:window; this->window; sc->全局的作用域链 ] 初始化变量对象,挂在到vo上面。全局的vo就是全局变量[window],这里就不存在激活对象了,或者认识激活对象就是VO vo===window: [ x ->undefined; fun->undefined; test->function_test,同时创建它的sc function_test[[scope]] = global.sc = [window] ] -------------------------全局代码执行--------------------------------------- 首先,赋值 y = 10; fun = test(); -->这里test函数执行---》重复上面的结构。 -----------------test代码进行EC初始化--------------------- 创建testEC = [ this--》window; 记住:只有XXX.test(), 这个this才指向XXX,否则都是window VO:testAO; 记住:只有函数,才有AO,全局的那个就是windows,这里VO就可以等同于AO了 sc:[testAO, testEC]; --> [testAO, window] 记住:在声明函数的时候。sc就是当前的上下文的sc。 在函数执行的时候,sc就是当前的函数的[活动对象+声明时的sc]就可以了。 区别就是差了一个活动对象。也就是激活对象。每次运行的时候,都有一个AO,哪怕是递归。 ] 变量实例化: 这里在解释一下变量实例化:就是将变量,形式参数,以及声明式函数,放入AO中,全局的时候,就是挂在到VO上,也就是window对象。 实例化的结果就是 testAO --> { y -> undefined; } 注意:我们return的那个是函数表达式,函数表达式,只有在执行的时候,才会创建EC。 --------------------------------------------------- ------------------test的函数执行------------------------- 首先 y = 2; 然后return 一个function。 这里创建这个匿名函数function的上下文。 --------------------------------------------------- ---------------------匿名函数function的上下文---------------------- 创建nfunEC = [ this-->window; ao: 没有,因为函数没有执行,这里只是声明。所以不存在活动对象。 sc:就是当前状态的sc fun.sc = testEC = [testAO, testEC] --->>> [testAO, window] ] 变量实例化:这里有形式参数x,但是因为没有执行,所以没有AO,无法挂在到上面。 (这就是一个问题?如何挂载AO,也就是说,这里如果没有AO,传入的x参数应该给谁?如何挂载变量a?函数变量应该在函数执行之前,就已经挂载了。) 函数表达式如果有参数,怎么办? -------------------------------------------------------------- 这里fun = test()函数的返回值,就是return的函数 然后,执行-->fun(x); ----------------------fun函数执行---------------------------------- 这里就是刚才的问题,这个由匿名函数赋值的fun,如何使用形式参数x的问题。 常规来说,代码执行阶段,变量,形式参数,和函数都已经初始化结束了。但是,上面函数表达式中,没有AO的存在,就无法挂在到AO上面, 其实哪里没有AO,但是有VO,就是windwo,但是测试window.x,果断是无法访问的。它肯定是不会绑定到window的。因为函数内部有作用域的概念,也可以理解为命名空间。

    所以: fun(10);执行的时候。 创建funEC = [ this-->window; vo: funAO; sc: [funAO, testAO.sc] --> [funAO, testAO, window]; ] ------------- 这里明显是不对的,不可能在函数执行的时候,才去创建EC和AO------------- 这里可以确定,声明函数应该是声明的时候,就已经创建了AO,而函数表达式,是在函数执行的时候。进行创建的AO。 ------------------------------------------------- ---------所以,一定是,声明函数了,就会创建一个AO,不论这个函数,是表达式,还时声明匿名函。否则函数表达式,无法挂在函数参数。就会出现参数解析的问题。 所以,执行匿名函数的时候,应该也会创建一个AO,去挂载传入的参数和函数哪部定义的变量。 所以应该在匿名函数执行的那个瞬间,就已经创建了AO AO : [ a : undefined; x : argunments[0]; ] 合并到FunSC里面 ,更新sc。 创建nfunEC = [ this-->window; nFunAO : [ a : undefined; x : argunments[0]; ] sc:[nFunAO, testAO.sc] = [nFunAO, testAO, window] ] 然后才是,fun(10);执行, x = 10; a = 10; alert(x + y +a); 这里查找y--》当前nFunAO没有,--》testAO,y = 2; 打印22. --------------这个例子可以证明,this是指向window的-------------------------- var y = 10; function test(){ this.y = 2; return function(x){ this.a = 10; console.log(window); alert(y + x + a); } } var fun = test(); fun(10); ------------------- window --> y: 2, a: 10 -------------------------------- -------------------------------------------- 最后应该注意一下,变量初始化的优先级问题;同名情况下会覆盖, 声明函数 > 形式参数 > 变量。 举个例子: function test(x, y) { console.log(x); //function x() {...} var x = 10; console.log(x); //10 function x () { console.log(1); } console.log(y); //20 var y = 20; console.log(y); //2 console.log(z); //undefined 因为变量声明的时候会赋值undefined,而不是30,只有在执行的时候才是30 var z = 30; console.log(m); //Uncaught ReferenceError: m is not defined

              m = 200;               // 这里证明全局变量没有任何用,js解析的时候,直接解析 [ var m ],所以。只有在执行的时候,才会创建m这个全局变量,并初始化!!!!

              console.log(n); //一样也是报错。说明不写var 定义的变量 与 不定义变量,在m = 200; 之前应用效果是一样的!!!
    } test(1,2);


    ------------------------------------------------------------
    11月25日更新:
      红色部分有问题,更正一下。函数声明的时候,就会创建scope,但是此时的scope是函数声明的上下文,并没有活动对象,
    而当函数执行的时候,才会将当前函数AO压入到scope中,然后变量初始化(形参,声明函数,变量)。绑定到执行时函数的AO里面。
    这样就没有问题了/

      

  • 相关阅读:
    Java框架spring学习笔记(十七):事务操作
    Java框架spring 学习笔记(十六):c3p0连接池的配置以及dao使用jdbcTemplate
    Java框架spring 学习笔记(十五):操作MySQL数据库
    Java框架spring 学习笔记(十四):注解aop操作
    Java框架spring 学习笔记(十三):log4j介绍
    Java框架spring 学习笔记(十二):aop实例操作
    Java框架spring 学习笔记(十一):aop相关概念
    Java框架spring 学习笔记(十):bean管理(注解和配置文件混合使用)
    Java框架spring 学习笔记(九):Spring的bean管理(@Required、@Component、@Autowired、@Resource注解)
    Java框架spring 学习笔记(八):注入对象类型属性
  • 原文地址:https://www.cnblogs.com/hgonlywj/p/4984267.html
Copyright © 2011-2022 走看看