函数参数名/变量名/函数名的同名情况

2,806 阅读3分钟

本文变量默认时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赋值


😥妈耶。


参考:github.com/mqyqingfeng…