函数内部改变传入的实际参数,外部对应的数据是否会改变,eval()的使用,块内声明函数的正确方法

168 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

第一题 函数内部改变传入的实际参数,外部对应的数据是否会改变

微信图片_20220823202737.jpg 我们先把代码写一下,var改成了let, 无影响

   let foo = { n: 1 }
            ; (function (foo) {
                console.log(foo.n);
                foo.n = 3
                 foo = { n: 2 }
                console.log(foo.n);
            })(foo)
            console.log(foo.n);

选项有:

A.1 2 3

B.undefined 2 1

C.报错

D.1 2 1

公布答案: A

image.png

  • 分析:
  • 整体分析:
  • 第一句是声明对象,第二句是立即执行函数,第三句控制台输出,立即执行函数不会异步,所以代码是自上而下执行的.
  • 局部分析:
  • 第一句是声明对象,对象中有一个键值对,由于是引用数据类型,foo存的是内存地址而不是值;
  • 第二句是立即执行函数,把foo作为实参传入函数,形参名也为foo,
  • 立即执行函数内部第一句是console.log(foo.n);是形参foo的n属性的属性值,毫无疑问是1,因为没有语句修改n的值
  • 接下来,foo.n=3修改了形参的n属性的属性值为3,由于实参foo是引用数据类型,foo存的是内存地址而不是值,所以修改形参foo的n属性名的属性值,实参foo也会更改.此时实参foo.n=3
  • 接下来foo={n:2},直接修改了形参foo的内存地址,此时形参foo.n=2
  • 所以console.log(foo.n);为2
  • 形参foo就和实参foo毫无关系了所以此时,实参的值不会变化,还是foo.n=3
  • 第三句 console.log(foo.n),输出的是实参foo的n属性的属性值,为3

注意:

  • 我认为题目容易出错的原因是,他把实参和形参名命名相同,这就给我们设了陷阱,于是我把函数的内部形参换成另一个,这样会更易理解,代码如下:
       let foo = { n: 1 }
            ; (function (obj) {
                console.log(obj.n);//1
                obj.n = 3
                 console.log(foo.n);//3 同时会改变foo.n
                obj = { n: 2 }
                console.log(obj.n);//2
            })(foo)
        console.log(foo.n);
  • 这样我们只需要理解obj.n = 3;改变obj.n的值同时也会改变foo.n就可以了

马后炮

  • 通过断点调试我们发现,形参foo为局部变量,实参foo为全局变量
  • 这也说明了印证了给形参foo={n:2}时,实参foo不改变仍然是foo:{n:3}

image.png

第二题 eval()的使用

微信图片_20220823202743.jpg 选项

A.4

B.undefined

C.10

D.3

代码如下


        eval(`{
         1+3;
        a = 2;
        x: break x;
        3;
        4 + 6;
        ;
        }`)
        console.log(
        eval(`{
         1+3;
        a = 2;
        x: break x;
        3;
        4 + 6;
        ;
        }`));

答案:C

image.png

eval()  函数会将传入的字符串当做 JavaScript 代码进行执行。

在块中多个语句执行时,一般后者会覆盖前者,但是;和break的返回值都是empty,无法覆盖任何值.3覆盖了4,10又覆盖了3,因此最终结果是10

MDN eval()介绍

第三题 块内声明函数的正确方法

image.png 微信图片_20220823202747.jpg 我们先把代码写一下,var改成了let,和const, 无影响

注意

  • 不要在块内声明函数,严格模式下会报错
  • 但若果一定要在块内声明函数,可以使用函数表达式来声明函数

B选项

        let x=1
        if(x){
            const f=function(){console.log(x)}
            f()
        }

设定的函数会在块级作用域中

image.png

C选项

        let x=1
        if(x){
            f=function(){console.log(x)}
            f()
        }

image.png

设定的函数不在块级作用域中 所以单选题,二者选B