本文变量默认时var声明,不讨论const和let的情况,因为const和let声明的变量标识符有重复会直接报错/死锁情况。
全局执行上下文:(变量/函数)
1.1
console.log(a);//ReferenceError: a is not defined
a = 1;全局执行上下文创建时,没有声明a变量,所以全局执行上下文的变量环境没有a
代码运行时,直接报错
1.2
console.log(a);//undefined
var a = 1;
console.log(a);//1全局执行上下文创建时,声明了a变量,所以全局执行上下文的变量环境有a(没运行代码的时候变量初始化为undefined)
代码运行时,变量提升(声明了才能提升)。
1.3
console.log(a);//function a()
function a(){}
var a = 1;
console.log(a);//1全局执行上下文创建时,声明了a变量和a函数,在此阶段,变量一般是变量名:undefined,函数则是函数名:函数引用,由于变量和函数同名,优先级是函数>变量,所以a:函数引用
代码运行时,变量和函数都提升了,第一行代码优先打印函数,随后第三行a标识符的映射改变,变为1
函数执行上下文:(变量/函数/函数参数)
本文不讨论当前函数执行上下文外的同名标识符情况,因为标识符都是按执行栈找的,当前函数执行上下文有的,就会优先使用函数内的,没有再向外面的执行上下文找。
只有变量和函数的时候,情况同全局执行上下文
1.1
function f1(a=99){
console.log(a);//99
var a = 1;
console.log(a);//1
}
f1()函数执行上下文创建时,声明了a参数和a变量,在此阶段,变量一般是变量名:undefined,函数参数则是参数名:实参或默认参数(既没有传实参,默认参数也没有设置的之后,默认参数为undefined),由于参数和变量同名,优先级是参数>函数>变量,所以a:实参或默认参数
代码运行时,函数参数和变量都提升了,第一行代码优先打印参数值,随后第三行a标识符的映射改变,变为1
1.2
function f1(a=99){
console.log(a);//99
function a(){}
console.log(a);//99
var a = 1;
console.log(a);//1
}
f1()function f1(a=99){
console.log(a);//99
a = function a(){};
console.log(a);//function a()
var a = 1;
console.log(a);//1
}函数执行上下文创建时,因为参数>函数>变量三者的优先级问题,a的值永远是参数值
代码运行时,变量赋值可以改变a标识符的映射,但函数的引用除非手动赋值改变,不然a函数永远无法调用,所以在同一层次的函数执行上下文中,定义的函数名不要和函数参数名重复!!!
补充(从沸点偷来的图)
看了下评论的解释:
在{}内声明函数,会在{}这个块级作用域声明一个a的局部变量。
然后原来的的function a(){}会执行 全局的a = 局部的a
就是说现在外部变量a=1(因为此时局部变量a等于1)
继续的 a=21 是给局部变量a赋值
😥妈耶。