最近看了一些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'
关于变量提升和函数提升,这里面有一些注意点
- 函数同名时,后面的函数会覆盖前面的函数
- 函数提升比变量提升的优先级高,且不会被变量声明覆盖
关于第一点函数同名时,后面的函数会覆盖前面的函数
,可以看以下示例代码
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,如下图所示:
当add()
函数被调用的时候,javascript引擎会编译该函数,并为其创建一个执行上下文,并且将执行上下文压入栈中,如下图所示。
当执行到b = 3
时,add函数的执行上下文中的变量环境中的b值会被设置为3。
当add()
函数执行完成之后,add函数的执行上下文从栈顶被弹出
因为栈是有大小的,当入栈的执行上下文超过一定数目,就会发生栈溢出
(出现错误为Maximun call stack size exceeded
),尤其在一些涉及到递归的代码里面,要注意栈溢出。