携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
第一题 函数内部改变传入的实际参数,外部对应的数据是否会改变
我们先把代码写一下,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
- 分析:
- 整体分析:
- 第一句是声明对象,第二句是立即执行函数,第三句控制台输出,立即执行函数不会异步,所以代码是自上而下执行的.
- 局部分析:
- 第一句是声明对象,对象中有一个键值对,由于是引用数据类型,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}
第二题 eval()的使用
选项
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
eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
在块中多个语句执行时,一般后者会覆盖前者,但是;和break的返回值都是empty,无法覆盖任何值.3覆盖了4,10又覆盖了3,因此最终结果是10
第三题 块内声明函数的正确方法
我们先把代码写一下,var改成了let,和const, 无影响
注意
- 不要在块内声明函数,严格模式下会报错
- 但若果一定要在块内声明函数,可以使用函数表达式来声明函数
B选项
let x=1
if(x){
const f=function(){console.log(x)}
f()
}
设定的函数会在块级作用域中
C选项
let x=1
if(x){
f=function(){console.log(x)}
f()
}
设定的函数不在块级作用域中 所以单选题,二者选B