一个变量的生成需要经历 创建、初始化、赋值三个阶段
let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。
const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。
let
1、
假设有如下代码:
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。
2、
fn2()
function fn2(){
console.log(2)
}
JS 引擎会有一下过程:
找到所有用 function 声明的变量,在环境中「创建」这些变量。
将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
开始执行代码 fn2()
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」
3、
{
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 还没「初始化」,所以不能使用(也就是所谓的暂时死区)
补充
1.
在进入一个执行环境后,先把 var 和 function 声明的变量前置, 再去顺序执行代码
是 var 声明在前还是 function 声明的在前?按先来后到,同名覆盖。当然如果一个变量已经有值,再 var 是无效的1
2
3
4
5
6
7
8
9
10
var fn
function fn(){}
console.log(fn) //function
function fn(){}
var fn //已经声明过 fn, 再 var 无效,并不会重置为 undefined
console.log(fn) //function
2.
函数在执行的过程中,先从自己内部找变量
如果找不到,再从创建当前函数所在的作用域去找, 以此往上1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var a = 1
function fn1(){
function fn2(){
console.log(a)
}
var a = 2
return fn2
}
var fn = fn1()
fn() //输出多少 2
////////////////////////////////
var a = 1
function fn1(){
var a = 2
return fn2
}
function fn2(){
console.log(a)
}
var fn = fn1()
fn() //输出多少 1
相关
1 | var a = {n:1}; |
a.x = a = {n:2};执行顺序
- a.x,这时a,b指向{n:1},增加x,属性,但值为undefined,即这时a,b为{n:1,x:undefined}
2.a={n:2},a这时指向{n:2},b依然为{n:1,x:undefined}
3.a.x = a;这时的x是{n:1,x:undefined}中的x,指向a,此时a指向{n:2}
1 | a==1 && a==2 && a==3 |
可能为true
关键在于==在比较两端之前会调用对象的valueof,toString等方法,只要a对象中的toString方法有递增值返回就可以实现1
2
3
4
5
6const a = {
i: 1,
toString: function () {
return a.i++;
}
}
立即执行函数的目的
造出一个函数作用域,防止污染全局变量
ES 6 新语法1
2
3{
let name
}