跳转至

浏览器中的js的执行机制

js中的变量提升

showName();
console.log(myname);
var myname = 'dou';
function showName(){
    console.log("showName函数被执行")
}

// "showName函数被执行"
// undefined
  1. 在执行过程中,如果使用了未声明的变量,那么JS的执行会报错
  2. 在一个变量定义之前使用它,不会出错,但是该变量的值会变成undefined,而不是定义时的值
  3. 在一个函数定义之前使用它,不会出错,且函数能正确执行

同样的方式,为什么变量和函数的处理方式不同?

模拟上述代码的执行过程:

/** 变量提升部分*/
var myname = undefined
// 函数的定义也会被提升
function showName(){
    console.log("showName函数被执行")
}
// 代码执行部分
showName();
console.log(myname);
myname = 'dou';

JavaScript代码的执行流程

一段JavaScript代码→编译阶段→执行阶段

编译阶段

编译阶段和变量提升存在什么关系?

变量提升部分

/** 变量提升部分*/
var myname = undefined
// 函数的定义也会被提升
function showName(){
    console.log("showName函数被执行")
}

执行代码部分

showName();
console.log(myname);
myname = 'dou';

在编译阶段主要是生成两部分内容:

执行上下文(全局执行上下文和函数的执行上下文)和可执行代码

执行上下文是JavaScript执行一段代码时的运行环境,比如调用一个函数,就会进入这个函数的执行上下文,确定该函数在执行期间用到的诸如this、变量、对象以及函数等。

全局变量环境对象--就是用于存储变量提升后的声明的数据

VariableEnvironment
    myname->undefined
    showName->function(){...}// 堆的内存地址,其中存储的是函数体内容

showName指向堆中的一个地址,其中存储的函数体内容

执行阶段

JavaScript引擎开始执行可执行代码,并且按照顺序一步一步的执行

代码中如果出现相同的变量或者函数怎么办?

function showName(){
    console.log("max")
}
showName()
function showName(){
    console.log("kaka")
}
showName()
// kaka
// kaka

分析:两个函数的声明都会被提升到顶部执行,第二个函数的声明会把第一个函数的声明给覆盖掉

  • JavaScript代码执行之前,需要先做变量提升。而之所以需要实现变量提升,是因为JavaScript代码在执行之前需要先编译
  • 在编译阶段,变量和函数是会先被存放到变量环境中,变量的默认值会被设置为undefined;在代码执行阶段JavaScript引擎会从变量环境中去查找自定义的变量和函数--就是所谓的执行上下文
  • 如果在编译阶段,存在两个相同的函数,那么最终存放在变量环境中的是最后定义的那个,这是因为后定义的会覆盖掉之前定义的
showName(); // 1
var showName = function(){
    console.log("2")
}
showName(); // 2
function showName(){
    console.log("1")
}
// 2

同名变量和函数的两点处理原则:

  • 如果是重名的函数,JavaScript编译阶段会选择最后声明的那个
  • 如果变量和函数同名,那么在编译阶段,变量的声明会被忽略

理解一下下面的代码

var showName = undefined
var showName = function(){
    console.log("2")
}
showName(); // undefined报错
function showName(){
    console.log("1")
}
// 编译阶段
VariableEnvironment
    showName->undefined
    showName->function(){...}
// 执行阶段
VariableEnvironment
    showName->undefined

条件语句中声明函数的变量提升是什么样的呢?

(function(){
    console.log(fn) // undefined
    if(true){
        console.log("hello")
        function fn(){
            return true
        }
    }
}
)

因为块级作用域中定义的变量或者函数在外部是是无法使用的,所以这里是undefined

ES规定函数不能在块级作用域中声明函数,