ECMAScript 函数的参数与大多数其他语言中的函数的参数有所不同。EMCAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就说,即便你定义的函数只接受两个参数,在调用这个时也不一定要传递两个参数。因为ECMAScript 中的参数在内部是用一个数组来表示的。函数接收到的始终是这个数组,而不关心数组中包含哪些参数。

在函数中,可以通过 arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数。arguments 对象只是与数组类似,但是并不是 Array 的实例。

  1. function foo () {
  2. console.log('arguments', arguments);
  3. console.log('typeOf(arugments)', typeof(arguments));
  4. }
  5. foo()
  6. foo(1, 2, 3)

执行结果:

  1. arguments {}
  2. typeOf(arugments) object
  3. arguments { '0': 1, '1': 2, '2': 3 }
  4. typeOf(arugments) object

从上面的例子可以看出 ECMAScript 函数的一个重要特点:命名的参数只是提供便利,但不是必须的。

关于 arguments 对象有两个特点:

  • arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数个数决定的。

  • arguments 的值,永远与对应命名参数的值保持同步。

下面的例子,会体现 arguments 的这两个特点。

  1. function foo (a, b) {
  2. console.log(arguments); // { '0': 1 }
  3. console.log(arguments.length) // 1
  4. console.log('a:', a); // 1
  5. console.log('b:', b); // undefined
  6. arguments[0] = 33;
  7. arguments[1] = 222;
  8. console.log(arguments) // { '0': 33, '1': 222 }
  9. console.log(arguments.length) // 1
  10. console.log(a); // 33
  11. console.log(b); // undefined
  12. }
  13. foo(1)

上面的例子修改了 arguments[0] 会自动反映到对应的命名参数。不过这并不是说读取这两个值会访问相同的内存空间,它们的内存空间是独立的,但他们的值会同步。

另外因为只传入了一个参数, arguments[1] 设置的值不会反映到命名参数中,因为 arguments 对象的长度是由传入的参数个数决定的。这个可以通过上面的输出结果,可以看出。

tips:arguments 的值,永远与对应命名参数的值保持同步,是在非严格模式下才成立的。如果实在严格模式下,则 arguments 的改变,是不会影响到参数的值。而参数值的变化,也不会影响到 arguments 的改变。

callee

arguments 这个对象有一个 callee 属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。

tips:callee 在严格模式下不能使用。