在做面试题之前,我们先搞清楚两个概念

  1. 执行上下文(execution context)
  2. 变量对象(variable object)

执行上下文

我们都知道JavaScript的作用域一共分三种

  • 全局作用域
  • 函数作用域
  • eval作用域

实际上每一次的函数调用都会有一个对应的执行环境,这个执行环境也叫做执行上下文。执行上下文是一个抽象的概念,函数每调用一次就会产生一个新的执行上下文。

下面我们通过一段代码来理解下执行上下文的顺序:

var fun0 = 'global context';
console.log(fun0); function fun1(){
console.log('fun1');
function fun2(){
console.log('fun2');
function fun3(){
console.log('fun3');
}
fun3();
}
fun2();
}
fun1(); // global context fun1 fun2 fun3

从上面代码结构我们可以看到在fun1内包含fun2,fun2中包含fun3,实际上是一层一层嵌套的。在代码执行的过程中,会先进入全局的fun0,当我们在调用fun1的时候控制权会从全局的fun0到fun1的这样一个执行上下文中,然后再调用fun2的时候控制权会从fun1到fun2,以此类推。当fun3调用结束以后会退回到fun2,当fun2调用结束之后会退回到fun1,当fun1调用结束后退回到fun0,等到整个代码都结束后就会依次输出global context fun1 fun2 fun3。这几个函数的每一次调用的时候都会产生一个对应的新的执行上下文。

变量对象

变量对象是一个抽象概念中的“对象”,不是JavaScript中真正意义上的对象。它用于存储执行上下文中函数声明、函数参数和变量。

VO按照如下的顺序存储:

  • 函数参数(若未传入,初始化该参数值为undefined)
  • 函数声明(若发生命名冲突,会覆盖)
  • 变量(初始化变量值为undefined,若发生命名冲突,会被忽略)

在函数中有点特殊的是:函数中有一个概念叫做激活对象(AO),AO就是在函数调用的时候会有一个特殊的arguments,arguments在初始化阶段会被放置到AO对象中,初始化之后AO对象又会被叫做VO对象。

下面我们来看一个例子:

function textVo(x,f){
var a = 1;
var b = 2;
function b(){};
function f(){};
var c = 'VO';
var e = function(){};
}
textVo(3);

上面代码再解析过程当中,按照VO存储的顺序会先将函数的参数x存储到AO中,然后是参数f,然后是函数b和函数f,再然后是变量a、b、c、e。

注意:

由于函数声明若发生命名冲突会覆盖,所以参数f会被函数f所覆盖,最后存入到AO对象中的是函数f

由于变量命名冲突会被忽略,所以变量b不会被存储到AO中

解析过程如下:

AO(textVo)={
x:3,
b:<ref to func "b">,
f:<ref to func "f">,
a:undefined,
c:undefined,
e:undefined
}

执行过程如下:

VO['a'] = 1;
VO['b'] = 2;
VO['c'] = 'VO';
VO['e'] = function e(){}; AO(textVo)={
x:3,
b:2,
f:<ref to func "f">,
a:1,
c:'VO',
e:function e(){};
}

JavaScript的执行过程其实可以理解为赋值的过程,由于函数f已经在解析过程中处理完了,在执行的过程中我们就可以直接忽略掉。

注意:在执行过程也就是赋值的过程中,发现b的值是2,这个时候会把值直接赋给已经存在AO中的函数b,最后输出的结果是b为2,函数b被替换掉了,这一块要注意下。

概念搞清楚之后,我们来看下面这道面试题。

alert(a);
a();
var a=3;
function a(){
alert(a);
alert(1);
}
alert(a);
a=6;
a();

第一眼看到这道题的感觉是不是:???(((φ(◎ロ◎;)φ)));现在我们掌握了执行上下文和变量对象之后再来看这道题就会变的很清晰。

解析:代码在解析阶段首先去找参数,我们这里没有参数所以直接忽略,接下来找到函数声明a放进VO中,然后找到变量a被忽略;

执行:

  • 第一步:进入全局执行上下文,运行alert(a),因为在解析阶段a已经存在于VO中,所以弹出的是函数a的源代码(alert里面的a是函数a的引用,是一个指针指向函数a);然后弹出全局上下文。
  • 第二步:第二个a是调用函数a,进入函数a的执行上下文,执行函数a内部的alert(a),这个时候的a还是函数a的指针,所以还是弹出函数a的源代码,然后弹出1;弹出函数a的执行上下文。
  • 第三步:进入全局执行上下文,给a赋值为3。
  • 第四步:执行alert(a),这个时候VO中的a已经被赋值为3了,所以弹出3。
  • 第五步:给a赋值为6。
  • 第六步:由于现在VO中的a已经被赋值为6了,所以在调用a()的时候会报错:Uncaught TypeError: a is not a function。

最后执行的结果为

ƒ a(){
console.log(a);
console.log(1);
}
ƒ a(){
console.log(a);
console.log(1);
}
1
3
Uncaught TypeError: a is not a function

以上就是我对执行上下文和变量对象的理解,不合理的地方望指出。

透过一道面试题来探探JavaScript中执行上下文和变量对象的底的更多相关文章

  1. javascript执行上下文和变量对象

    执行上下文(execution context): 执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念. js语言是一段一段的顺序执行,这个“段”其实就是我们说的这个执行上 ...

  2. JavaScript学习系列之执行上下文与变量对象篇

    一个热爱技术的菜鸟...用点滴的积累铸就明日的达人 正文 在上一篇文章中讲解了JavaScript内存模型,其中有提到执行上下文与变量对象的概念.对于JavaScript开发者来说,理解执行上下文与变 ...

  3. 前端学习 第二弹: JavaScript中的一些函数与对象(1)

    前端学习 第二弹: JavaScript中的一些函数与对象(1) 1.apply与call函数 每个函数都包含两个非继承而来的方法:apply()和call(). 他们的用途相同,都是在特定的作用域中 ...

  4. 深入理解javascript中执行环境(作用域)与作用域链

    深入理解javascript中执行环境(作用域)与作用域链 相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行 ...

  5. 再看javascript执行上下文、变量对象

    突然看到一篇远在2010年的老文,作者以章节的形式向我们介绍了ECMA-262-3的部分内容,主要涉及到执行上下文.变量对象.作用域.this等语言细节.内容短小而精悍,文风直白而严谨,读完有酣畅淋漓 ...

  6. JavaScript内部原理系列-变量对象(Variable object)

    概要 我们总是会在程序中定义一些函数和变量,之后会使用这些函数和变量来构建我们的系统.然而,对于解释器来说,它又是如何以及从哪里找到这些数据的(函数,变量)?当引用一个对象的时候,在解释器内部又发生了 ...

  7. JavaScript中如何判断两变量是否“相等”?

    1 为什么要判断? 可能有些同学看到这个标题就会产生疑惑,为什么我们要判断JavaScript中的两个变量是否相等,JavaScript不是已经提供了双等号“==”以及三等号“===”给我们使用了吗? ...

  8. javascript中执行环境和作用域(js高程)

    执行环境(execution context,为简单起见,有时也成为“环境”)是javascript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境 ...

  9. javascript中函数声明、变量声明以及变量赋值之间的关系与影响

    javascript中函数声明.变量声明以及变量赋值之间的关系与影响 函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 ...

随机推荐

  1. Oracle JDBC:驱动版本区别与区分 [转]

    classes12.jar,ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别,之间的差异 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle  ...

  2. Object.assign()

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 说明 Ob ...

  3. 小白的Python之路 day1 表达式if ... else ,while循环,for循环

    表达式if ... else 一.用户登陆验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 提示输入用户名和密码    # 验 ...

  4. 【python】内部函数

  5. 【python】字符串

    >>> str1="welcom to China">>> str1[2:4]'lc'>>> str1[7]'t'>&g ...

  6. 【python】入门:打印字符串、简单计算

  7. VM环境下Linux虚拟机扩展存储空间操作方法总结

    用VMwareware虚拟机安装的 Linux 系统剩余空间不足,造成软件无法正常安装.如果重新装一遍系统就需要重新配置好开发环境和软件的安装配置. 一.空间扩展  (1)打开VMware,选择Edi ...

  8. Charles 抓包工具使用部分问题总结

    一. You may need to configure your browser or application to trust the Charles Root Certificate. See ...

  9. 瞎j8封装第二版之数据库连接池

    写得很蛋疼,本来想支持多线程的,奈何对多线程和连接池理解着实太菜: 所以,起码是能拿到连接了... 但是还是不太懂这个连接池 我也是半抄别人的,以后再搞一搞这个吧. 先是配置文件 理想是很丰满的,奈何 ...

  10. 重写JS的鼠标右键点击菜单

    重写JS的鼠标右键点击菜单 该效果主要有三点,一是对重写的下拉菜单的隐藏和显示:二是屏蔽默认的鼠标右键事件:三是鼠标左键点击页面下拉菜单隐藏. 不多说,上html代码: 1 <ul id=&qu ...