前端高质量知识(三)-JS变量对象详解
在JavaScript中,我们肯定不可避免的需要声明变量和函数,可是JS解析器是如何找到这些变量的呢?我们还得对执行上下文有一个进一步的了解。
在上一篇文章中,我们已经知道,当调用一个函数时(激活),一个新的执行上下文就会被创建。而一个执行上下文的生命周期可以分为两个阶段。
创建阶段
在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向代码执行阶段
创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。

从这里我们就可以看出详细了解执行上下文极为重要,因为其中涉及到了变量对象,作用域链,this等很多人没有怎么弄明白,但是却极为重要的概念,因此它关系到我们能不能真正理解JavaScript。在后面的文章中我们会一一详细总结,这里我们先重点了解变量对象。
变量对象(Variable Object)
变量对象的创建,依次经历了以下几个过程。
建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。

根据这个规则,理解变量提升就变得十分简单了。在很多文章中虽然提到了变量提升,但是具体是怎么回事还真的很多人都说不出来,以后在面试中用变量对象的创建过程跟面试官解释变量提升,保证瞬间提升逼格。
在上面的规则中我们看出,function声明会比var声明优先级更高一点。为了帮助大家更好的理解变量对象,我们结合一些简单的例子来进行探讨。
- // 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: {...}, //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解,我做了这样的处理
- foo: <foo reference> // 表示foo的地址引用
- a: undefined
- }
未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。
这样,如果再面试的时候被问到变量对象和活动对象有什么区别,就又可以自如的应答了,他们其实都是同一个对象,只是处于执行上下文的不同生命周期。
- // 执行阶段
- VO -> AO // Active Object
- AO = {
- arguments: {...},
- foo: <foo reference>,
- a: 1
- }
因此,上面的例子demo1,执行顺序就变成了这样
- function test() {
- function foo() {
- return 2;
- }
- var a;
- console.log(a);
- console.log(foo());
- a = 1;
- }
- test();
再来一个例子,巩固一下我们的理解。
- // demo2
- function test() {
- console.log(foo);
- console.log(bar);
- var foo = 'Hello';
- console.log(foo);
- var bar = function () {
- return 'world';
- }
- function foo() {
- return 'hello';
- }
- }
- test();
- // 创建阶段
- VO = {
- arguments: {...},
- foo: <foo reference>,
- bar: undefined
- }
- // 这里有一个需要注意的地方,因为var声明的变量当遇到同名的属性时,会跳过而不会覆盖
- // 执行阶段
- VO -> AO
- VO = {
- arguments: {...},
- foo: 'Hello',
- bar: <bar reference>
- }
需要结合上面的知识,仔细对比这个例子中变量对象从创建阶段到执行阶段的变化,如果你已经理解了,说明变量对象相关的东西都已经难不倒你了。
全局上下文的变量对象
以浏览器中为例,全局对象为window。
全局上下文有一个特殊的地方,它的变量对象,就是window对象。而这个特殊,在this指向上也同样适用,this也是指向window。
- // 以浏览器中为例,全局对象为window
- // 全局上下文
- windowEC = {
- VO: window,
- scopeChain: {},
- this: window
- }
除此之外,全局上下文的生命周期,与程序的生命周期一致,只要程序运行不结束,比如关掉浏览器窗口,全局上下文就会一直存在。其他所有的上下文环境,都能直接访问全局上下文的属性。
前端高质量知识(三)-JS变量对象详解的更多相关文章
- JS变量对象详解
JS变量对象详解 开年之后工作热情一直不是很高,这几天一直处于消极怠工状态.早上不想起床,起床了不想上班.明明放假之前工作热情还一直很高,一直心心念念的想把小程序项目怼出来,结果休假回来之后画风完全不 ...
- 前端高质量知识(四)-JS详细图解作用域链与闭包
攻克闭包难题 初学JavaScript的时候,我在学习闭包上,走了很多弯路.而这次重新回过头来对基础知识进行梳理,要讲清楚闭包,也是一个非常大的挑战. 闭包有多重要?如果你是初入前端的朋友,我没有办法 ...
- 前端高质量知识(五)-JS详细图解全方位解读this
在这之前,我们需要来回顾一下执行上下文. 在前面几篇文章中,我有好几个地方都提到执行上下文的生命周期,为了防止大家没有记住,再次来回顾一下,如下图. 执行上下文生命周期 在执行上下文的创建阶段,会分别 ...
- 前端高质量知识(一)-JS内存空间详细图解
变量对象与堆内存 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因为JavaScript具有自动垃圾回收机制,所 ...
- 前端高质量知识(二)-JS执行上下文(执行环境)详细图解Script
先随便放张图 我们在JS学习初期或者面试的时候常常会遇到考核变量提升的思考题.比如先来一个简单一点的. console.log(a); // 这里会打印出什么? var a = 20; PS: 变量提 ...
- js变量类型详解
<html> <title>js变量类型详解</title> <meta http-equiv="content-type" conten ...
- JS window对象详解
window 是客户端浏览器对象模型的基类,window 对象是客户端 JavaScript 的全局对象.一个 window 对象实际上就是一个独立的窗口,对于框架页面来说,浏览器窗口每个框架都包含一 ...
- JS DATE对象详解
1.建立时间对象:可获取年,月,日,星期,时,分,秒 var d = new Date(); console.log(d.getFullYear()+'年'+d.getMonth()+'月'+d.ge ...
- js课程 1-3 Javascript变量类型详解
js课程 1-3 Javascript变量类型详解 一.总结 一句话总结:js对象点(属性方法),json对象冒号(属性方法).属性和方法区别只有一个括号. 1.json对象中的函数的使用? 函数名 ...
随机推荐
- Spring Boot中JPA如何实现按日期合计
1. 用queryDsl方法 JPAQueryFactory.select( Projections.fields(OrderCountByDayBean.class, qOrder.amount.s ...
- 在IntelliJ IDEA中配置Google Java Code Style及代码格式化快捷键
google-java-format plugin should intercept the “Reformat Code” action in IDEA (Ctrl+Alt+L) and apply ...
- Java StringBuffer
String是不变类,用String修改字符串会新建一个String对象,如果频繁的修改,将会产生很多的String对象,开销很大.因此java提供了一个StringBuffer类,这个类在修改字符串 ...
- sql的几种常用锁简述
比较全的文章地址保存下:http://www.cnblogs.com/knowledgesea/p/3714417.html SELECT * FROM dbo.AASELECT * FROM dbo ...
- 下载,安装oracle数据库以及navicat连接数据库
一.学习时所遇问题: 1.在下载之前以为oracle不是免费的,但是后来才知道oracle对于个人学习时是免费的,可以到官网下载安装.在下载时由于要注册oracle官网,所以尝试了好几遍,才成功下载o ...
- java——修改txt文件中某一行的内容
今天无意间看到java.io中有一个类:RandomAccessFile,可以在文件的任意位置进行读写操作,想到我之前写的一个小项目,想在txt中修改某一行的内容,都是从头遍历txt文件,修改这一行的 ...
- Python Pandas -- Panel
Pandas 中一维 series, 二维DataFrame, 三维Panel class pandas.Panel(data=None, items=None, major_axis=None, m ...
- hadoop install start-dfs.sh 失败
linux:ubuntu 16.04 LTS hadoop version: 2.7.3 JDK: java-9-open-jdk issue: start-dfs.sh start-dfs.sh:c ...
- getElementsByTagName 、 getElementsByName 、getElementById区别
WEB标准下可以通过getElementById(), getElementsByName(), and getElementsByTagName()访问DOCUMENT中的任一个标签: getEle ...
- JavaSE---线程同步
1.当多个线程同时访问同一个数据时,容易出现线程安全问题,必须进行线程同步: 2.解决方案: 1.1 Java的多线程引入了 同步监视器 ,使用同步监视器的通用方法就是 同步代码块 //线程开始 ...