JS 中的变量提升
参考不同的文章, 整理成为自己可理解的内容
文章原地址
出现的代码运行线上地址 javascript-visualizer
首先来看小例子
console.log('name: ', name) // undefined
console.log('age : ', age ) // undefined
console.log('sayHi ;', sayHi) // f sayHi()
var name = '小火车'
var age = 24
function sayHi () {
return "sayHI"
}
打印出来的结果都是undefined
先了解JS
的运行机制: 首先是创建阶段, 其次是执行阶段
在创建阶段的时候,JS
引擎就会创建全局的window和this
对象, 将所有的变量声明都赋予一个默认值undefined
,所有的函数声明都被存入到内存中, 在执行阶段的时候,JS
引擎就会将真实的值赋值给声明的变量
-
在创建阶段的时候,
JS引擎
主要做的事情1.创建了全局的
window
对象
2.创建了this
对象
3.给变量和函数分配内存
4.给变量赋默认值undefined
,把函数声明放进内存中 -
在执行阶段,
JS
引擎就会一步一步的执行代码, 将内存中的变量赋予真实值
再回头看先前的代码
console.log('name: ', name) // undefined
console.log('age : ', age ) // undefined
console.log('sayHi ;', sayHi) // f sayHi()
var name = '小火车'
var age = 24
function sayHi () {
return "sayHI"
}
当JS
的引擎开始执行console.log()
代码的时候,这个时候已经就处于执行阶段了, 之前的创建阶段已经执行完毕, 变量的声明已经被赋予了默认值undefined
, 同时函数的声明已经在内存中定义了, 因此name
和age
都是被赋予了undefined
,sayHi
也正是内存中函数的引用
何为变量提升: 在JS
引擎创建阶段给变量赋予默认值undefined
的过程就是变量提升
何为变量提升: 在JS
引擎创建阶段给变量赋予默认值undefined
的过程就是变量提升
何为变量提升: 在JS
引擎创建阶段给变量赋予默认值undefined
的过程就是变量提升
函数执行上下文
-
函数执行上下文是在函数被调用的时候就被创建出来了
-
在函数执行上下文的时候
JS
引擎创建的不是window
对象, 而是arguments
对象1.创建一个
arguments
对象
2.创建this
对象
3.给变量和函数赋值
4.给变量赋予默认值undefined
, 把函数声明放进内存 -
执行函数
var name = "小火车" var age = 24 function sayHi() { console.log("小火车") } sayHi()
-
可以看到在执行到
sayHi()
函数调用的时候,JS
引擎在创建函数上下文的创建阶段的时候创建了arguments
对象和this
对象, 因为函数中没有任何的变量,JS
引擎就不需要进行变量的提升和函数内存的分配 -
当
sayHi()
函数执行完之后, 函数的执行过程就消失了, 因为JS
引擎在函数调用的时候就会创建一个执行栈(也叫调用栈)
,每当函数被调用, 就会创建一个新的执行上下文, 并且加入到执行栈中(调用栈)
,当函数执行完毕之后就会从执行栈
中弹出
-
JS
的单线程在执行函数嵌套函数的代码时,每一个新的函数调用(函数执行上下文),都会被嵌套到最初的函数执行上下文中,形成了一个调用栈
作用域
小例子
function a() {
var name = "小火车"
}
a()
console.log(name)
- 在
JS
引擎的创建阶段可以看到name
这个变量是没有声明的
- 在
JS
引擎执行到了a()
函数的时候, 函数内部就会出现函数的执行上下文,在创建阶段创建了arguments
对象和this
对象,name
变量就发生了变量提升现象,赋予默认值undefined
- 之后到了执行阶段,
name
变量就会被赋予真实的数据 - 最后函数执行完毕,
a()
函数的执行上下文结束, 在调用栈中被弹出 - 再执行
console.log(name)
的时候,报错ReferenceError: name is not defined
- 通常情况下,函数内部定义的变量在函数外部访问不到, 传入函数的所有参数都被定义为局部变量存在于函数的执行上下文中, 简单来说作用域就是变量的可访问之处
小例子2
var name = "小火车"
function a() {
console.log(name)
}
a()
打印出来的结果仍旧是小火车
- 当执行函数中的执行上下文找不到相应的局部变量的时候,
JS
引擎就会到最接近的上级执行上下文查找, 这条查找链会一直延伸到全局上下文中, 如果仍旧找不到JS
引擎就会抛出一个引用错误, 这个过程就是作用域链