【JS】块级作用域的面试题到底有多变态

727 阅读3分钟

前言

函数执行会形成一个私有的作用域,但是如果符合以下条件,就会多产生一个作用域:

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

第三题

第三题与第二题同理,仔细研究第二题解析即可,同样的也可以使用断点测试进行观察

题目过于变态,不多做研究,感兴趣的话可以深入研究总结一下~