arguments对象和参数的互相引用

学生问了一个问题

function funcA(arr) {
  arr[0] = arr[2]
}
function funcB(a, b, c=3) {
  c = 10
  funcA(arguments)
  return a + b + c
}
console.log(funcB(1,1,1)) // 12

而如果funcB的c没有默认值

function funcA(arr) {
  arr[0] = arr[2]
}
function funcB(a, b, c) {
  c = 10
  funcA(arguments)
  return a + b + c
}
console.log(funcB(1,1,1)) // 21

以上两段代码的结果不同,这种现象是为什么?

这涉及到两个知识点:

1)这是因为严格模式和非严格模式的时候arguments对象的行为有所不同:

非严格模式:arguments对象和形参是互相引用

function func(a) {
  arguments[0] = 99;   // 更新了arguments[0] 同样更新了a
  console.log(a);
}
func(10); // 99

function func(a) {
  a = 99;              // 更新了a 同样更新了arguments[0]
  console.log(arguments[0]);
}
func(10); // 99

严格模式:arguments对象和形参互相无关

function func(a) {
  "use strict"
  arguments[0] = 99;   // 不会更新a
  console.log(a);
}
func(10); // 10

function func(a) {
  "use strict"
  a = 99;              // 不会更新arguments[0]
  console.log(arguments[0]);
}
func(10); // 10

非严格模式下的这个行为是很讨厌的,这也是为什么我们不喜欢潜规则,如果你不小心,它就会把东西弄得很复杂。

2)当函数中使用了参数的解构、默认值或…rest参数,则函数内部自动按严格模式解释

参考:MDN-Arguments对象

尝试运行下面这个例子,观察结果

<script>
  function func(a) {
    arguments[0] = 99 // 更新了arguments[0] 同样更新了a
    console.log(a)
  }
  func(10) // 10
</script>

<script>
  function func(a) {
    arguments[0] = 99 // 更新了arguments[0] 同样更新了a
    console.log(a)
  }
  func(10) // 99
</script>

<script>
  function func(a=1) {
    arguments[0] = 99 
    console.log(a)
  }
  func(10) // 10
</script>

<script>
  function func(a, ...b) {
    arguments[0] = 99 
    console.log(a)
  }
  func(10) // 10
</script>