• 从JavaScript执行上下文理解变量提升


    一直在看JavaScript的书,有几个知识点对新手来说很疑惑:

    1. 执行上下文
    2. 作用域链
    3. this

    JavaScript是一门解释性语言,不需要编译,是可以直接拿到运行环境中运行。

    执行上下文

      要解释执行上下文就先得说说JavaScript的内存机制;虽然JavaScript的运行环境一般都自带了GC装置,所以不用太操心内存泄漏的这个蛋疼的问题。但是当我们每当声明一个变量时,这个变量到底存在内存中的哪里?一般来说在JavaScript中基础数据类型(null  undefined string number Boolean)是存在栈中,而引用类型(array object)是存在堆内存中。eg:

    var a1 = 0;   // 变量对象
    var a2 = 'this is string'; // 变量对象
    var a3 = null; // 变量对象
    var b = { m: 20 }; // 变量b存在于变量对象中,{m: 20} 作为对象存在于堆内存中
    var c = [1, 2, 3]; // 变量c存在于变量对象中,[1, 2, 3] 作为对象存在于堆内存中

    从图中可以看出引用类型的的值是保存了一个堆内存中的一个地址,所以每次操作时都是对源数据进行操作!

    而执行上下文呢?根据《JavaScript高级编程》中指出,EC(执行时环境)中主要有三部分  1:VO(变量对象)  2:SC(作用域链)   3:this

    在运行JavaScript时最先入栈的就是全局EC,若有其他的新的执行环境创建则依次入栈,运行完时则出栈。

    变量对象的创建,依次经历了以下几个过程。

    1. 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。

    2. 检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。

    3. 检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。

    总的来说就是function优先级比var高,var声明的变量永远都是undefined,而对于引用类型和函数则是堆内存地址! 

    
    
    // demo01
    function test() {    console.log(a);    console.log(foo());    var a = 1;    function foo() {  return 2;
        }
    }
    test();

    在上例中,我们直接从test()的执行上下文开始理解。全局作用域中运行test()时,test()的执行上下文开始创建。为了便于理解,我们用如下的形式来表示

    创建过程
    testEC = {    // 变量对象    
    VO: {},    
    scopeChain: {},    
    this: {}}// 因为本文暂时不详细解释作用域链和this,所以把变量对象专门提出来说明// 
    
    VO 为 Variable Object的缩写,即变量对象
    VO = {   
     arguments: {...},    
    foo: <foo reference>  // 表示foo的地址引用 
    a: undefined
    }

    未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。

    这样,如果再面试的时候被问到变量对象和活动对象有什么区别,就又可以自如的应答了,他们其实都是同一个对象,只是处于执行上下文的不同生命周期。

    // 执行阶段VO ->  AO   // Active ObjectAO = {
        arguments: {...},
        foo: <foo reference>,
        a: 1}

    因此,上面的例子demo1,执行顺序就变成了这样

    function test() {    
    function foo() {        return 2;   }   
     var a;    
    console.log(a);   
    console.log(foo());
     a = 1;
    }
    
    test();
     
  • 相关阅读:
    [LeetCode] Insert Interval
    java 可变參数
    谈谈单元測试之(二):測试工具 JUnit 3
    我的csdn博客搬家了
    leetcode 229: Majority Element II
    向MapReduce转换:生成用户向量
    《31天成为IT服务达人》最新文件夹
    SD卡读写之FileNotFoundException: /storage/emulated/0object.txt: open failed: ENOENT (No such file or dir
    当写烂代码的人离职之后....
    JavaSE Map的使用
  • 原文地址:https://www.cnblogs.com/duyingxuan/p/6406380.html
Copyright © 2020-2023  润新知