a(); // 1
var a = "hello world"; //2
console.log(a); // 3
function a() {
// 4
console.log("inner a function 1");
}
var a = "hello, tomorrow"; // 5
console.log(a); // 6
function a() {
// 7
console.log("inner a function 2");
}
a(); // 8
执行结果是:
/*
inner a function 2
hello world
hello, tomorrow
报错 a is not a function
*/
分析下:
编译阶段
1,函数调用不做处理
2, 有 var 声明变量,在执行环境中变量环境对象上创建 a 变量并赋值为 undefined.
Variable Environent:
a -> undefined;
3, 函数调用,不做处理
4, JS 引擎发现有同名 function 定义的函数 a,把函数定义存储到堆中,并且在变量环境对象中查找是否有 a 属性,有 a,然后把 a 的值指向该函数的在堆中的位置。此时变量环境对象变成(类似这样):
Variable Environent:
a -> function () { console.log ('inner a function 1')};
5, 有 var 声明变量,在执行环境中变量环境对象上查找是否存在 a 属性,发现存在并 y 有值,不做处理。
6, 不做处理
7, JS 引擎发现有同过 function 定义的函数 a,把函数定义存储到堆中,并且在变量环境对象中查找是否有 a 属性,有 a,然后把 a 的值指向该函数的在堆中的位置。此时变量环境对象变成(类似这样):
Variable Environent:
a -> function () { console.log ('inner a function 2')};
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
前言
我们来看下面这一段代码。
如果你写过 js,那就知道,这段代码不会报错,会正常输出
undefined undefined
。如果不能理解,不要着急,我们删除
var str = 'hello world'
,再执行:现在就会报错了,
str is not defined
。这是为什么呢?如果不知道不要紧,下边我们就来了解下,要了解 JavaScript 的运行方式,我们就要先了解下变量提升。变量提升(Hosting)
在介绍变量提升之前,我们先通过以下两个例子来讲解 JS 中的声明和赋值。
在 es6 之前,JS 都是通过 var 来声明变量。
这一句等价于
下面这段代码是一个完整的函数声明,没毛病。
这段代码是一个声明变量和赋值的过程,相当于
所谓的变量提升,是指 JavaScript 在执行的过程中,JavaScript 引擎把变量提升和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置值为 undefined。
JavaScript 执行流程
从概念的字面上来看,“变量提升”意味着变量和函数的声明会在物理层移动到代码的最前面。但其实是:变量和函数声明在代码里的位置是不会改变的,而且在编译阶段被 JavaScript 引擎放入内存中。JS 代码编译完成之后才会进入执行阶段。
大致流程就是:一段 JavaScript 代码 => 编译阶段 => 执行阶段
下面来看下详细的流程,还是以上边的例子为例
执行流程图如下:
从上图可以看出,输入一段 JS 代码,经过编译后,会生成两部分内容:执行上下文(Execution context)和可执行代码。
执行上下文
是指 JS 执行一段代码时的运行环境,比如调用一个函数,就会进入这个函数的执行上下文,确定该函数在执行期间的用到变量如 this、变量、对象、函数等。
在执行上下文中存在一个变量环境的对象(Variable Environment),该对象中保存了变量提升的内容,比如上面代码中变量 str 和函数 print 都保存在该对象中。
类似这样:
接下来逐行分析下代码:
编译阶段
这样就生成了变量环境对象,接着 JS 引擎会把声明之外的代码编译成字节码(可执行代码),也就是下面这一段模拟代码:
执行阶段
JS 引擎开始执行“可执行代码”,按照顺序一行一行的执行,过程如下:
console.log(str)
, JS 引擎继续在变量环境对象中查找 str,此时 str 在变量环境对象中的值为 undefined, 所以输出 undefined.str = 'hello world!';
这是一个赋值操作,把'hello world!'赋值给 str, 赋值结束后变量环境对象变成:整个流程大致差不多这样。
有个问题,如果代码中存在多个相同的变量和函数时怎么办?
示例代码:
执行结果是:
分析下:
编译阶段
然后执行可执行代码: