2.JS执行上下文和变量对象
文章目录
- 执行上下文栈
- 函数上下文
- 变量对象
- 执行过程
- 进入执行上下文
- 代码执行
- 两个例子
- 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
对象。这个对象中存储了所有传入函数的参数。
执行过程
执行上下文中的代码会分为两个阶段进行处理:
- 进入执行上下文
- 代码执行
进入执行上下文
此时的变量对象会以以下顺序初始化:
函数的所有形参(函数上下文中):
由名称和对应值组成的一个变量对象的属性被创建
没有实参,属性值设为
undefined
函数声明:
由名称和对应值(function-object)组成的一个变量对象的属性被创建
如果变量对象已经存在相同名称的属性,则完全替换这个属性。
变量声明:
由名称和对应值(
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
}
形参 a
和 arguments
这时候已经有赋值了,而变量还是 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执行上下文和变量对象相关推荐
- java函数ao活动对象_JavaScript中的执行上下文和变量对象
执行上下文(Execution Context) JavaScript代码执行的过程,包括编译和执行两个阶段,编译就是通过词法分析,构建抽象抽象语法树,并编译成机器识别的指令,在JavaScript代 ...
- 一、 函数调用栈,执行上下文及变量对象
前言 为什么会有这篇文章? 在书籍或博客上,我们经常会看到「作用域链」.「闭包」.「变量提升」等概念,说明一个问题 -- 它们很重要. 但很多时候,对于这些概念,看的时候觉得自己已经明白了,可过不了多 ...
- JavaScript学习系列之执行上下文与变量对象篇
一个热爱技术的菜鸟...用点滴的积累铸就明日的达人 正文 在上一篇文章中讲解了JavaScript内存模型,其中有提到执行上下文与变量对象的概念.对于JavaScript开发者来说,理解执行上下文与变 ...
- 串讲-解释篇:作用域,作用域链,执行环境,变量对象,活动对象,闭包
这篇接:理论篇:作用域,作用域链,执行环境,变量对象,活动对象,闭包 看例子: function compare(value1, value2) {if (value1 < value2) {r ...
- JavaScript——执行环境、变量对象、作用域链
前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体.通过上网查资料,特来总结,以备回顾和修正. 目录: EC(执行环境或 ...
- js - 执行上下文和作用域以及闭包
首先,咱们通常被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混.那我们一一来揭秘这些名 ...
- JavaScript执行环境 + 变量对象 + 作用域链 + 闭包
闭包真的是一个谈烂掉的内容.说到闭包,自然就涉及到执行环境.变量对象以及作用域链.汤姆大叔翻译的<深入理解JavaScript系列>很好,帮我解决了一直以来似懂非懂的很多问题,包括闭包.下 ...
- JavaScript之变量对象
前言 在上篇<JavaScript之执行上下文栈>中讲到,当 JavaScript 代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution ...
- js执行oracle函数吗,执行javascript函数
JS--函数 JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function 函数名([参数]){ 执行的代码: } 当调用该函数时,会执行函数 ...
最新文章
- Maven3.x 插件开发入门
- Keras框架训练模型保存及载入继续训练
- 可以弹的钢琴,很不错(转)
- GRE词汇乱序版-夹生的词汇3
- linux php常用命令,php调用Linux系统常用命令
- 工信部印发《信息安全产业“十二五”发展规划》
- C# 多页打印简单实现
- SpringCloud的微服务网关:zuul(理论)
- python2与pyrhon3的区别,python—文件操作,函数练习题
- Car2go 的前端框架选择
- mysql安装教程【安装版】
- 基于RV1126平台imx291分析 --- media部件注册 imx291
- JavaScript之浏览器大战
- Vue 引入阿里巴巴矢量图标库 (详细)
- 体育专业国培计算机感言,计算机国培心得体会.doc
- 使用python进行序列的GC含量的统计
- 自然语言处理(一)——中英文分词
- ZYNQ入门,EBAZ4205开发平台从头开始搭建
- 高一数学试题-2022年秋期末试卷
- android和ios测试环境搭建,iOS自动化测试环境搭建
热门文章
- NativeXml (1):下载、安装、测试
- 见到了“公司”定义一个Company类,那么见到了“字段”是不是也可定义一个Column类?...
- datagrid加checkbox实现分页不丢失选择的记录 (转)
- 安全攻防技能——安全基础概念
- 低复杂度 - 服务网格的下一站
- 不再写死,SpringBoot实现动态增删启停定时任务
- 浅谈 UC 国际信息流推荐
- 全球Top5互联网巨头崛起秘诀,真相竟然是?
- 忽悠马云10亿的骗子,还了阿里4500亿:做对事赢一场,跟对人赢一生!
- 我是如何在2年内逆袭成为BAT年薪40W的资深开发工程师的?