• js执行上下文(由浅入深)


    每一个函数都有自己的执行上下文EC(执行环境 execution context),并且每个执行上下文中都有它自己的变量对象VO(Variable object),用于存储执行上下文中的变量 、函数声明 、函数参数,这解释了js如何找到我们定义的函数和变量。并且函数是js中唯一一个能创建出作用域的,注意:for,if()else()不能创建作用域。我们通过以下几个例子说明为什么函数和变量的声明会被前置,为什么匿名函数表达式的不可以在外面调用。

    var a = 18;
    f1();
    function f1(){
     var b=9;
     console.log(a);  //undefined
     console.log(b);  //9
     var a = '123';
    }

    因为在f1中,在此函数还未执行时变量a,b会被提前声明,也就是说可以理解为下面的代码

    var a = 18;
    f1();
    function f1(){
     var b;
     var a;
     b = 9;
     console.log(a);
     console.log(b);
     a = '123';
    }

    如果想进一步理解内部的运行机制,可以用如下方法:

    在此案例中,f1函数的作用域链有两个对象,一个是全局变量对象,一个是f1变量对象。

    VO (globalContext) = {

      a: 18,

      f1: <ref to function>

    }

    1.变量初始化阶段

    VO (f1 functionContext) = {

      a: undefined,

      b: undefined

    }

    2.代码执行阶段

    VO (f1 functionContext) = {

      a: undefined,

      b: 9

    }

    再来两个js经典题

    function fn(a){
        console.log(a);  //function(){}
        var a = 2;
        function a(){};
        console.log(a); //2
    }
    fn(1);

    我们知道,在运行fn之前,变量和function都会提前声明,但是function会覆盖变量(在不赋值的前提下),

    通过以上案例,我们可以总结如下规律:

    VO按照如下顺序填充:
     1.  函数参数  (若未传入,初始化该参数值为undefined)
     2.  函数声明  (若发生命名冲突,会覆盖)
     3.  变量声明  (初始化变量值为undefined,若发生命名冲突,会忽略。)

    注意:变量初始化(被声明)和变量根本不在一个变量对象里是有区别的,如果用console打印前者会显示undefined,而后者会报一个"ReferenceError: gg is not defined"。

    比如

    第一个只有一个全局上下文

    VO (globalContext) = {

      fn: <ref to function>

    }

    因为没有执行fn,所以里面的变量读取不到,第二个通过声明被前置,打印undefined.(只有var的变量才能被前置)

    为了让大家充分了解执行上下文,再来一个例子。

    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。 

    最后来一个压轴的

    alert(a);   //undefined
    alert(b);   //undefined
    alert(x);   //function x(){}
    var x = 10;
    alert(x);   // 10
    x = 20;
    function x(){}
    alert(x);   // 20
    if (true) {
      var a = 1;
    } else {
      var b = true;
    }
    alert(a);   //1
    alert(b);   //undefined

    首先声明一点,js是没有块级作用域的,所以if{}else{}里面的变量即使不执行,他们的声明也会前置,所以第一个和第二个alert为undefined,对于第三个alert,因为先是x这个变量前置,然后x又变成了function,前面说过了,函数声明如果发生冲突会覆盖变量声明(可以理解为function的优先级更高),所以第三个弹出function,第四个赋值为10,第五个x=20覆盖x=10,第六个因为执行了if,所以给a赋值弹出1,最后一个还是undefined。

  • 相关阅读:
    skywalking请求头传输协议
    一篇文章带你搞懂SkyWalking调用链追踪框架
    zuihou-admin-cloud很经典的一个微服务开发平台,能够详细的看里面的视频https://www.kancloud.cn/zuihou/zuihou-admin-cloud/1411215
    skywalking权限验证功能
    哔哩哔哩中Openshift红帽培训
    ElasticSearch中文社区视频教程地址
    浅谈一些有趣的区间问题
    浅谈区间最小点覆盖
    洛谷 P1325 雷达安装
    CF12B Correct Solution?
  • 原文地址:https://www.cnblogs.com/ssh-007/p/5064699.html
Copyright © 2020-2023  润新知