札早早

导航

关于执行上下文--整理

 JS执行上下文,也可以理解为代码的运行环境或者作用域,分别为以下三种

1,全局上下文,引擎最先进入的就是这个环境

2,函数级别的代码,当执行函数(就是函数调用),运行内代码

3,Eval代码,在Eval函数中运行的代码

每当调用一个函数(不管是否重复),一个新的执行上下文会被创建出来

具体分为两个阶段

第一个阶段:建立阶段(1,建立 arguments对象(检查当前上下文的参数),

 2,参数,

3,函数声明,

4,变量声明;

,5建立作用域链

6,确定this的值

这个时刻,引擎会检查函数中的参数,声明的变量以及内部函数,然后基于这些信息建立执行上下文对象(executionContextObj)。在这个阶段,variableObject对象,作用域链,以及this所指向的对象都会被确定。

第二个阶段:代码执行阶段(变量赋值,函数引用,执行其它代码)

var a = 10;
var b = 30;
function fn(x){
    var a = 100;
    var c = 20;
    function f1(x){
        var a = 1000;
        var d = 10;
        console.log(x);
    }
    f1(100); // 100
    f1(200); // 200
}
fn(250);

  

函数上下文中的变量对象

Arguments对象是活动对象的一个属性,它包括如下属性

1,callee--指向当前函数的引用

2,length  --真正传递的参数个数(arguments.lenth是真正的传参个数,foo.length是参数)

3,properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。

properties-indexes内部元素的个数等于arguments.length. properties-indexes 的值和实际传递进来的参数之间是共享的。

function foo(x, y, z) {
 
  // 声明的函数参数数量arguments (x, y, z)
  alert(foo.length); // 3
 
  // 真正传进来的参数个数(only x, y)
  alert(arguments.length); // 2
 
  // 参数的callee是函数自身
  alert(arguments.callee === foo); // true
 
  // 参数共享
 
  alert(x === arguments[0]); // true
  alert(x); // 10
 
  arguments[0] = 20;
  alert(x); // 20
 
  x = 30;
  alert(arguments[0]); // 30
 
  // 不过,没有传进来的参数z,和参数的第3个索引值是不共享的

  z = 40;
  alert(arguments[2]); // undefined
 
  arguments[2] = 50;
  alert(z); // 40
 
}
 
foo(10, 20);
这个例子的代码,在当前版本的Google Chrome浏览器里有一个bug  — 即使没有传递参数z,z和arguments[2]仍然是共享的。

  几个例子

var a = 10;
function fn() {
  console.log(a);
}
function bar(f){
  var a = 20;
  f();
}
		bar(fn); // 10  
// 因为fn()函数虽然在调用之前就进行了预编译状态。所以a=10

  

function fn() {
  console.log(a);
}
function bar(f){
  a = 20; //没加var  这是全局变量 
  f();
}
bar(fn); // 20

  

1 var b;
2 console.log(b); //b是undefined
3 (function b(){
4     b = 20;
5     console.log("b:"+b);
6             // b:function b(){b = 20;console.log("b:"+b);}
7 })();
8 console.log(b); //b是undefined 
//加上自己的理解吧(并不是一定正确)
// 在这个自调用函数之中,函数名和一个属性的赋值都是b的名称。 b=20 是全局变量,自调用函数相当于函数的声明,函数声明的提升
顺序大于 变量的提升,所以b赋值为 function b(){}
// 当 b=20 改为var b = 20;时 结果就是 b:20
1 var b;
2 console.log(b); //b是undefined
3  (function a(){
4         b = 20;
5     console.log("b:"+b);// b:20
6 })();
7         console.log(b); // 20    
8 //以下是我自己的理解, 这次函数名字和赋值b 并不冲突。所以 b=20是全局变量,
var b;
function b(){};
console.log(b) //function b(){}  因为变量b没赋值。所以函数优先

//另一个例子
var b = 20;
function b(){};
console.log(b) //20  变量赋值 则函数声明不会影响到值。因为函数声明比变量声明的等级高,都会提到最前面。变量的赋值是最后面
        var scope = "global scope";
        function checkscope(){
            var scope = "local scope";
            function f(){
                console.log(scope); //local scope
            }
            return f();
        }
        checkscope();
        

        var scope = "global scope";
        function checkscope(){
            var scope = "local scope";
            function f(){
                console.log(scope);  //local scope
            }
            return f;
        }
        checkscope()();    
//区别在哪呢
//第二个的入栈顺序为
/*
        ECStack.push(checkscope> functionContext);
        ECStack.pop();
        ECStack.push(f> functionContext);
        ECStack.pop();

*/             
        function test(a, b) {
          var c = 10;
          function d() {}
          var e = function _e() {};
          (function x() {});
        }
         
        test(10); // call

        
        
         
        // AO(test) = {
        //   a: 10,
        //   b: undefined,
        //   c: undefined,
        //   d: <reference to FunctionDeclaration "d">
        //   e: undefined
        // }; 

        // AO['c'] = 10;
        // AO['e'] = <reference to FunctionExpression "_e">;


    // 关于变量,还有一个重要的知识点。变量相对于简单属性来说,变量有一个特性(attribute):{DontDelete},这个特性的含义就是不能用delete操作符直接删除变量属性。

        a = 10;
        alert(window.a); // 10
         
        alert(delete a); // true
         
        alert(window.a); // undefined
         
        var b = 20;
        alert(window.b); // 20
         
        alert(delete b); // false
         
    alert(window.b); // still 20
    // // 但是这个规则在有个上下文里不起走样,那就是eval上下文,变量没有{DontDelete}特性。

    eval('var a = 10;');
    alert(window.a); // 10
     
    alert(delete a); // true
     
    alert(window.a); // undefined


    function test(a,b){ 
        var c = 10; 
        function d(){} 
        var e = function _e(){}; 
        (function x(){}); 
            b = 20;     
        } 
    test(10);
    // 提示:因为此函数中有形参b,所以在变量初始化阶段会b:undefined,如果没有形参b,会报错 b is not defined。

 

 

以上有参考其他文献

posted on 2017-11-16 19:03  札早早  阅读(257)  评论(0编辑  收藏  举报