文章目录

  • 执行上下文栈
  • 函数上下文
    • 变量对象
  • 执行过程
    • 进入执行上下文
    • 代码执行
    • 两个例子
      • 1
      • 2

  JS 是单线程语言,因此执行顺序是顺序执行,不过 JS 引擎在执行 JS 代码的时候并不是逐行执行,而是一段一段地分析执行,先是编译阶段,然后才是执行阶段。

  具体的体现可看例子:

例一 变量提升

  我们在未定义 foo 之前就使用了它,结果不会报错,而是会为 undefined,随后, foo 会像我们定义的那样先是输出 foo1 ,后输出 foo2

console.log(foo);   // undefinedvar foo = function() {console.log('foo1');
}foo();  // foo1var foo = function() {console.log('foo2');
}foo();  // foo2

例二 函数提升

  在定义之前就调用 foo ,不会发生错误,且后定义的 foo 会覆盖先定义的同名函数。

foo();  // foo2function foo() {console.log('foo1');
}foo();  // foo2function foo() {console.log('foo2');
}foo();  // foo2

例三 声明优先级:函数 > 变量

  首先,函数提升的优先级会高于变量提升,因此开始输出 foo2,然后 foo 被重新定义,接下来都输出 foo1

foo();  // foo2var foo = function() {console.log('foo1');
}foo();  // foo1function foo() {console.log('foo2');
}foo();  // foo1

执行上下文栈

  JS 使用了执行上下文栈(Execution context stack,ESC)来管理执行上下文。

  这个在 1-JS执行上下文和执行栈 中就有提到

  关于执行上下文栈,有以下例子:

代码1

var scope = 'global scope';function checkScope() {var scope = 'local scope';function f() {return scope;}return f();
}console.log(checkScope());

代码2

var scope = 'global scope';function checkScope() {var scope = 'local scope';function f() {return scope;}return f();
}console.log(checkScope()());

 这两段代码的输出都为 local scope。(选中看答案)

  原因很简单,是因为 JS 采用的是词法作用域,函数的作用域基于函数创建的位置。

  用 《JS 权威指南》的回答就是:

JS 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。

嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f() 这种绑定在执行 f() 时依然有效。

  而这两段代码的不同之处在于其执行上下栈的变化不一样:

  使用伪代码表示,第一段代码的执行上下文栈是这样的:

ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();

  而第二段代码为:

ECStack.push(<checkscope> functionContext);
ECStack.pop();
ECStack.push(<f> functionContext);
ECStack.pop();

函数上下文

变量对象

  变量对象(variable object,VO) 是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。

  在函数上下文中,使用活动对象(activation object,AO)来表示变量对象。

  变量对象和活动对象实际上是一个东西,它们的区别在于:

  • 变量对象(VO)是规范上或是 JS 引擎上实现的,并不能在 JS 环境中直接访问
  • 当进入到一个执行上下文后,这个变量对象才会被激活,所以叫活动对象(AO),这时候活动对象上的各种属性才能被访问。

  在调用函数时,会为其创建一个 Arguments 对象,并自动初始化剧本变量 arugments,指代 Arguments 对象。这个对象中存储了所有传入函数的参数。

执行过程

  执行上下文中的代码会分为两个阶段进行处理:

  1. 进入执行上下文
  2. 代码执行

进入执行上下文

  此时的变量对象会以以下顺序初始化:

  1. 函数的所有形参(函数上下文中):

    • 由名称和对应值组成的一个变量对象的属性被创建

    • 没有实参,属性值设为 undefined

  2. 函数声明

    • 由名称和对应值(function-object)组成的一个变量对象的属性被创建

    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性。

  3. 变量声明

    • 由名称和对应值(undefined)组成一个变量对象的属性被创建

    • 如果变量名称跟已经声明的形参或函数相同,则遍历声明不会干扰已存在的这类属性。

如下代码:

function foo(a) {var b = 2;function c() {}var d = function() {};b = 3;
}foo(1);

  进入执行上下文后,这个时候的(活动对象) AO 是:

AO = {arguments: {0: 1,length: 1},a: 1,b: undefined,c: reference to function c() {},d: undefined
}

  形参 aarguments 这时候已经有赋值了,而变量还是 undefined

代码执行

  这个阶段会顺序执行代码,并修改变量对象的值,执行完成后 AO 如下:

AO = {arguments: {0: 1,length: 1},a: 1,b: 3,c: reference to function c() {},d: reference to FunctionExpression "d"
}

两个例子

1

function foo() {console.log(a);a = 1;
}foo();

  上面的代码会报错:Uncaught ReferenceError: a is not defined

  这是因为函数中的 a 没有通过 var 关键字声明,所以不会被存放在 AO 中。

  在执行 console.log 的时候,AO 的值是:

AO = {arguments: {length: 0}
}

  没有 a 的值,然后就去全局对象中寻找,也没找到,因此报错了。

  如果在函数中使用了 var 声明的话:

console.log(a)
var a = 1;

  那么 console 会打印 undefined

2

console.log(foo);function foo() {console.log('foo');
}var foo = 1;

  上面的代码会打印函数,而不是 undefined

  这是因为在进入执行上下文时,首先会处理函数声明,其次处理变量声明,如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已存在的这类属性。


REF:https://muyiy.cn/blog/1/1.2.html#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87

2.JS执行上下文和变量对象相关推荐

  1. java函数ao活动对象_JavaScript中的执行上下文和变量对象

    执行上下文(Execution Context) JavaScript代码执行的过程,包括编译和执行两个阶段,编译就是通过词法分析,构建抽象抽象语法树,并编译成机器识别的指令,在JavaScript代 ...

  2. 一、 函数调用栈,执行上下文及变量对象

    前言 为什么会有这篇文章? 在书籍或博客上,我们经常会看到「作用域链」.「闭包」.「变量提升」等概念,说明一个问题 -- 它们很重要. 但很多时候,对于这些概念,看的时候觉得自己已经明白了,可过不了多 ...

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

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

  4. 串讲-解释篇:作用域,作用域链,执行环境,变量对象,活动对象,闭包

    这篇接:理论篇:作用域,作用域链,执行环境,变量对象,活动对象,闭包 看例子: function compare(value1, value2) {if (value1 < value2) {r ...

  5. JavaScript——执行环境、变量对象、作用域链

    前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体.通过上网查资料,特来总结,以备回顾和修正. 目录: EC(执行环境或 ...

  6. js - 执行上下文和作用域以及闭包

    首先,咱们通常被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混.那我们一一来揭秘这些名 ...

  7. JavaScript执行环境 + 变量对象 + 作用域链 + 闭包

    闭包真的是一个谈烂掉的内容.说到闭包,自然就涉及到执行环境.变量对象以及作用域链.汤姆大叔翻译的<深入理解JavaScript系列>很好,帮我解决了一直以来似懂非懂的很多问题,包括闭包.下 ...

  8. JavaScript之变量对象

    前言 在上篇<JavaScript之执行上下文栈>中讲到,当 JavaScript 代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution ...

  9. js执行oracle函数吗,执行javascript函数

    JS--函数 JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function 函数名([参数]){ 执行的代码: } 当调用该函数时,会执行函数 ...

最新文章

  1. Maven3.x 插件开发入门
  2. Keras框架训练模型保存及载入继续训练
  3. 可以弹的钢琴,很不错(转)
  4. GRE词汇乱序版-夹生的词汇3
  5. linux php常用命令,php调用Linux系统常用命令
  6. 工信部印发《信息安全产业“十二五”发展规划》
  7. C# 多页打印简单实现
  8. SpringCloud的微服务网关:zuul(理论)
  9. python2与pyrhon3的区别,python—文件操作,函数练习题
  10. Car2go 的前端框架选择
  11. mysql安装教程【安装版】
  12. 基于RV1126平台imx291分析 --- media部件注册 imx291
  13. JavaScript之浏览器大战
  14. Vue 引入阿里巴巴矢量图标库 (详细)
  15. 体育专业国培计算机感言,计算机国培心得体会.doc
  16. 使用python进行序列的GC含量的统计
  17. 自然语言处理(一)——中英文分词
  18. ZYNQ入门,EBAZ4205开发平台从头开始搭建
  19. 高一数学试题-2022年秋期末试卷
  20. android和ios测试环境搭建,iOS自动化测试环境搭建

热门文章

  1. NativeXml (1):下载、安装、测试
  2. 见到了“公司”定义一个Company类,那么见到了“字段”是不是也可定义一个Column类?...
  3. datagrid加checkbox实现分页不丢失选择的记录 (转)
  4. 安全攻防技能——安全基础概念
  5. 低复杂度 - 服务网格的下一站
  6. 不再写死,SpringBoot实现动态增删启停定时任务
  7. 浅谈 UC 国际信息流推荐
  8. 全球Top5互联网巨头崛起秘诀,真相竟然是?
  9. 忽悠马云10亿的骗子,还了阿里4500亿:做对事赢一场,跟对人赢一生!
  10. 我是如何在2年内逆袭成为BAT年薪40W的资深开发工程师的?