var,let,const,function声明的「创建、初始化和赋值」过程
2017-08-23 14:01
337 查看
假设有如下代码:
在执行 fn 时,会有以下过程(不完全):
进入 fn,为 fn 创建一个环境。
找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
将这些变量「初始化」为 undefined。
开始执行代码
x = 1 将 x 变量「赋值」为 1
y = 2 将 y 变量「赋值」为 2
也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。
这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。
接下来来看 function 声明的「创建、初始化和赋值」过程
假设代码如下:
JS 引擎会有一下过程:
找到所有用 function 声明的变量,在环境中「创建」这些变量。
将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
开始执行代码 fn2()
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。
接下来看 let 声明的「创建、初始化和赋值」过程
假设代码如下:
我们只看 {} 里面的过程:
找到所有用 let 声明的变量,在环境中「创建」这些变量
开始执行代码(注意现在还没有初始化)
执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
执行 x = 2,对 x 进行「赋值」
这就解释了为什么在 let x 之前使用 x 会报错:
原因有两个
console.log(x) 中的 x 指的是下面的 x,而不是全局的 x
执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的暂时死区)
看到这里,你应该明白了 let 到底有没有提升:
let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。
最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。
这四种声明,用下图就可以快速理解:
所谓暂时死区,就是不能在初始化之前,使用变量。
故事依然没有结束,这周我在知乎上问了一个问题:如何理解 let x = x 报错之后,再次 let x 依然会报错?
这个问题说明:如果 let x 的初始化过程失败了,那么
x 变量就将永远处于 created 状态。
你无法再次对 x 进行初始化(初始化只有一次机会,而那次机会你失败了)。
由于 x 无法被初始化,所以 x 永远处在暂时死区(也就是盗梦空间里的 limbo)!
有人会觉得 JS 坑,怎么能出现这种情况;其实问题不大,因为此时代码已经报错了,后面的代码想执行也没机会。
function fn(){ var x = 1 var y = 2 } fn()
在执行 fn 时,会有以下过程(不完全):
进入 fn,为 fn 创建一个环境。
找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
将这些变量「初始化」为 undefined。
开始执行代码
x = 1 将 x 变量「赋值」为 1
y = 2 将 y 变量「赋值」为 2
也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。
这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。
接下来来看 function 声明的「创建、初始化和赋值」过程
假设代码如下:
fn2() function fn2(){ console.log(2) }
JS 引擎会有一下过程:
找到所有用 function 声明的变量,在环境中「创建」这些变量。
将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
开始执行代码 fn2()
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。
接下来看 let 声明的「创建、初始化和赋值」过程
假设代码如下:
{ let x = 1 x = 2 }
我们只看 {} 里面的过程:
找到所有用 let 声明的变量,在环境中「创建」这些变量
开始执行代码(注意现在还没有初始化)
执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
执行 x = 2,对 x 进行「赋值」
这就解释了为什么在 let x 之前使用 x 会报错:
let x = 'global' { console.log(x) // Uncaught ReferenceError: x is not defined let x = 1 }
原因有两个
console.log(x) 中的 x 指的是下面的 x,而不是全局的 x
执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的暂时死区)
看到这里,你应该明白了 let 到底有没有提升:
let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。
最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。
这四种声明,用下图就可以快速理解:
所谓暂时死区,就是不能在初始化之前,使用变量。
完了吗?
故事依然没有结束,这周我在知乎上问了一个问题:如何理解 let x = x 报错之后,再次 let x 依然会报错?这个问题说明:如果 let x 的初始化过程失败了,那么
x 变量就将永远处于 created 状态。
你无法再次对 x 进行初始化(初始化只有一次机会,而那次机会你失败了)。
由于 x 无法被初始化,所以 x 永远处在暂时死区(也就是盗梦空间里的 limbo)!
有人会觉得 JS 坑,怎么能出现这种情况;其实问题不大,因为此时代码已经报错了,后面的代码想执行也没机会。
相关文章推荐
- javascript精雕细琢(一):var let const function声明的区别
- JavaScript变量声明var,let.const及区别浅析
- javascript中var let const三种变量声明方式详解
- var与ES6中const、let声明的变量的区别
- C++类对象创建过程(分配空间、赋值和初始化、对象初始化顺序、虚函数表指针)
- 【ES6系列】let-var-function 声明和作用域问题
- 变量声明关键字var、let、const
- C++类对象创建过程(分配空间、赋值和初始化、对象初始化顺序、虚函数表指针)
- C++类对象创建过程(分配空间、赋值和初始化、对象初始化顺序、虚函数表指针)
- JS中的变量声明——var,let,const的区别
- javascript中var let const三种变量声明方式
- angularJS2 变量声明 var let const
- angularJS2 变量声明 var let const
- Java数组声明、创建、初始化
- 为什么对于类的const成员,只能使用初始化列表,而不能在构造函数内部进行赋值操作
- Web端 es6(基础一) let var const 的区别
- 5分钟掌握var,let和const异同
- java9:一维数组的声明,创建,初始化(single-dimensional arrays)
- const member function can return non-const type member vars
- Linux内核--网络协议栈深入分析(四)--套接字内核初始化和创建过程