前言
函数执行会形成一个私有的作用域,但是如果符合以下条件,就会多产生一个作用域:
1、如果形参里面有赋值默认值
2、函数里面有私有变量(只有 var 、let、const可以,function一般不行,但是如果同时也做了形参,则也会形成两个作用域)就会把大括号包括起来的函数体当成一个代码块,看成块级作用域,这样就会有两个作用域
注: 上下文 等价于 作用域
三道变态面试题对比
var x = 1;
function func(x,y=function anonymous1(){x=2}){
x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
答案:2 1
var x = 1;
function func(x,y=function anonymous1(){x=2}){
var x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
答案:3 1
var x = 1;
function func(x,y=function anonymous1(){x=2}){
var x = 3;
var y = function anonymous2(){
x = 4
};
y();
console.log(x);
}
func(5);
console.log(x);
答案:4 1
分析
第一题分析
/* EC(g)
VO:
x = 1
function func:func
func(5)
*/
/*
EC(func5)
AO:
x = 5 =>3 =>2
y:anonymous1
x = 3 此处改变的是私有的
*/
/*
EC(y)
AO: 无
x = 2 向上级作用域查找
*/
所以输出的私有变量 x 是 2 ,然后全局变量 x 还是1
第二题分析
在私有作用域里面,又形成了块级作用域,块级作用域的上级作用域是私有作用域
EC(g)
VO: x = 1
func = func
/*
func(5) 形成了私有作用域
EC(func)
AO:
x = 5 => 2
y = anonymous1
*/
/*在私有作用域中形成私有块级作用域
而且会把开始的私有的形参赋值也给块级一份
EC(block)
x = 5 => 3
*/
/*
y()又形成私有作用域
EC(y)
AO:无
x = 2 没有私有变量 x 需要向上级作用域查找
y函数在私有作用域EC(func)中创建的
因此上级作用域是私有作用域,而不是块级作用域
所以只将私有作用域EC(func)中的变量 x 变为 2
*/
最终输出的是块级作用域中的变量 x 是3,全局的变量 x 还是1
总结
有一个函数,里面有形参:
1、形参只有一个赋值默认值
2、在此作用域中出现了let、var、const...(出现过私有变量的这种行为)就会产生两个作用域,相当于多形成了一个私有的块级作用域,而且会把开始的私有的形参赋值也给块级一份
符合这两个条件就会在私有作用域中多形成一个块级作用域,而且会把开始的私有的形参赋值也给块级一份。
断点测试
在代码中加入debugger断点,打开浏览器,刷新一下,然后在浏览器中打开控制台Sources, 按F11,逐句代码进行执行,观察作用域(scope)和变量的变化。
可以看到最终的块级作用域的 x 是 3,私有作用域的 x 是2,输出的是块级的 x ,所以输出3,全局的 x 没有变化,还是 1
第三题
第三题与第二题同理,仔细研究第二题解析即可,同样的也可以使用断点测试进行观察
题目过于变态,不多做研究,感兴趣的话可以深入研究总结一下~