最近看了一些javascript相关的知识,打算整理一下

变量提升

先来看一段示例代码

foo()
console.log(name)
var name = 'test'
function foo() {
    console.log('function foo be called');
}

可以看到打印出的结果是:

function foo be called
undefined

可以看到变量name在声明之前就被调用了,这在其他语言里面是会报错的,但是在javascript里面却打印出undefined,这是因为用var声明的变量发生了变量提升

在javascript代码执行之前,需要先进行编译。在编译的时候,就把变量的声明和函数的声明提升到了“代码开头”,即上方的代码可以理解为这样:

/**
 * 变量提升和函数提升部分
 */
var name = undefined
function foo() {
	console.log('function foo be called');
}


/**
 * 可执行代码部分
 */
foo()
console.log(name)
name = 'test'

关于变量提升和函数提升,这里面有一些注意点

  1. 函数同名时,后面的函数会覆盖前面的函数
  2. 函数提升比变量提升的优先级高,且不会被变量声明覆盖

关于第一点函数同名时,后面的函数会覆盖前面的函数,可以看以下示例代码

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

function foo() {
    console.log('function 2 called');
}

可以看到打印结果是:

function 2 called
undefined

上方的示例代码中有两个叫foo的函数,打印结果可以印证在变量提升和函数提升时,函数同名时,后面的函数会覆盖前面的函数这个结论


关于第二点函数提升比变量提升的优先级高,且不会被变量声明覆盖,可以看以下示例代码:

console.log(foo)
console.log(name)
var name = 'test'
function foo() {
    console.log('function 1 called');
}
var foo = 'blablabla'
function foo() {
    console.log('function 2 called');
}

可以看到打印结果是:

function foo() {
    console.log('function 2 called');
}
undefined

上方的示例代码中,有两个叫foo的函数,一个叫foo的变量,可以看到第一行代码console.log(foo)打印出来foo是个函数,而且是两个函数里面位于后面的函数。印证了在变量提升和函数提升时,函数提升比变量提升的优先级高,且不会被变量声明覆盖这个结论

执行上下文

当一段代码被执行时,javascript引擎会先对其进行编译,并创建执行上下文。执行上下文可以理解为当前代码的运行环境,有以下三种情况:

  • 全局环境:代码运行起来后会首先进入全局环境,并且在整个页面的生命周期内,全局执行上下文只有一份
  • 函数环境:当调用一个函数的时候,函数体内的代码会被编译,并且创建函数执行上下文。一般情况下,当函数执行结束之后,创建的函数执行上下文会被销毁。
  • eval环境:当使用eval函数的时候,eval的代码也会被编译,并创建执行上下文

在一个javascript程序中,可能会出现多个执行上下文,javascript引擎会以的方式来管理他们。

看下面这段示例代码:

示例代码

一开始的时候,全局上下文被创建,并被压入栈底。如下图所示:

全局上下文被创建,并被压入栈底

当全局上下文被压入栈底之后,javascript引擎便开始执行全局代码了。执行a = 2之后,全局执行上下文的变量环境中的a的值会被设置为2,如下图所示:

全局执行上下文的变量环境中的a的值会被设置为2

add()函数被调用的时候,javascript引擎会编译该函数,并为其创建一个执行上下文,并且将执行上下文压入栈中,如下图所示。

add函数的执行上下文被创建并被压入栈中

当执行到b = 3时,add函数的执行上下文中的变量环境中的b值会被设置为3。

add函数的执行上下文中的变量环境中的b值会被设置为3

add()函数执行完成之后,add函数的执行上下文从栈顶被弹出

add函数执行完成后执行上下文从栈顶弹出

因为栈是有大小的,当入栈的执行上下文超过一定数目,就会发生栈溢出 (出现错误为Maximun call stack size exceeded),尤其在一些涉及到递归的代码里面,要注意栈溢出。