今天在浏览面试题的时候遇到了一道百思不得其解的题目,话不多说,直接上题目,看看几人能做对
function side(arr) {
arr[0] = arr[2];
}
function func1(a, b, c = 3) {
c = 10;
side(arguments);
console.log(a + b + c);
}
function func2(a, b, c) {
c = 10;
side(arguments);
console.log(a + b + c);
}
func1(1, 1, 1);
func2(1, 1, 1);
正确输出是:
func1(1, 1, 1); // 12
func2(1, 1, 1); // 21
我想应该有人和我有一样的疑惑,这是个怎么回事呢?抱着打破砂锅问到底的学习态度,今天是一定要给他整明白的。 于是我便找资料,终于发现了有人问出了同样的问题,并且评论区给到了回答 [原文链接] (ac.nowcoder.com/discuss/721…)
于是我顺着它的解释,前往了mdn进行查阅,发现确实是这样说的 MDN链接
不包含剩余参数、默认参数和解构赋值
顺着它的话,我对严格模式下和非严格模式下的同样的代码进行测试,如下:
"use strict";
function func(a) {
arguments[0] = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 99 }
// 99
// 10
function func(a) {
arguments[0] = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 99 }
// 99
// 99
发现严格模式下对arguments对象进行操作,值确实会被改变,但是并没有影响到a,但是非严格模式下对arguments对象进行操作会同步影响到a。那么如果是对入参a直接进行操作会不会影响arguments呢
"use strict";
function func(a) {
a=99
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 10 }
// 10
// 99
function func(a) {
a=99
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 99 }
// 99
// 99
😯发现严格模式下对a进行修改并不会影响arguments对象,但是在非严格模式下对a的修改会映射到arguments对象。从而得出结论:
在严格模式下,函数没有包含剩余参数、默认参数和解构赋值,参数的改变并不会改变arguments对象,同时arguments对象的改变也无法改变参数的值。
当非严格模式下,函数没有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值会跟踪参数的值,二者存在映射关系,会同步修改。
包含剩余参数、默认参数和解构赋值
以默认参数为例, 对严格模式和非严格模式再次进行测试:
"use strict";
function func(a=55) {
arguments[0] = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 99 }
// 99
// 10
function func(a=55) {
arguments[0] = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 99 }
// 99
// 10
可以看到,二者的答案是一样的,先再来看下直接操作a参数会怎样再得出结论:
"use strict";
function func(a=55) {
a = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 10 }
// 10
// 99
function func(a=55) {
a = 99;
console.log(arguments);
console.log(arguments[0]);
console.log(a);
}
func(10);
// [Arguments] { '0': 10 }
// 10
// 99
😯对比二者可以看到,从而得出结论:
当严格模式中的函数有包含剩余参数、默认参数和解构赋值,参数的改变并不会改变arguments对象,同时arguments对象的改变也无法改变参数的值。
当非严格模式中的函数有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值不会跟踪参数的值,二者不存在映射关系,不会同步修改。
原题解析
function side(arr) {
arr[0] = arr[2];
}
function func1(a, b, c = 3) {
c = 10;
side(arguments); // arguments此时传递是 [Arguments] { '0': 1, '1': 1, '2': 1 }
console.log(a + b + c);
}
function func2(a, b, c) {
c = 10;
side(arguments); // arguments此时传递是 [Arguments] { '0': 1, '1': 1, '2': 10 }
console.log(a + b + c);
}
func1(1, 1, 1); // 12
func2(1, 1, 1); // 21
在func1中,因为包含默认参数c,所以不被arguments对象追踪,不会同步更新,对c=10,不会影响到arguments的值,所以在进行side函数中arr[2]的值仍然是1,同时因为arr[0]也就是对应映射的a并不属于剩余参数、默认参数和解构赋值, 它的赋值会影响到a的值, 因此最后相加是1+1+10 = 12
在func2中,因为不包含默认参数,所以会被arguments对象追踪,会同步更新,对c=10,会让arguments[2]=10,所以在进行side函数中arr[2]的值10赋值给了arr[0],同时因为arr[0]也就是对应映射的a并不属于剩余参数、默认参数和解构赋值, 它的赋值会影响到a的值,因此最后相加是10+1+10 = 21
总结:
1.严格模式下,无论什么参数, 参数的改变并不会改变arguments对象,同时arguments对象的改变也无法改变参数的值。
2.非严格模式下,函数没有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值会跟踪参数的值,二者存在映射关系,会同步修改。反之亦然。
3.好记性不如烂笔头,这是第一篇笔记,但不会是最后一篇.