详解JS之Arguments对象

目录
  1. 概述
  2. Demo
    1. arguments.callee
    2. arguments.length
    3. arguments[]
    4. 鸭式辩型

概述

Arguments 对象已经不再是函数的属性了, 它是函数内部的本地变量, 包括如下属性:

  1. callee — 指向当前函数的引用
  2. length — 真正传递的参数个数
  3. properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。 properties-indexes内部元素的个数等于arguments.length. properties-indexes 的值和实际传递进来的参数之间是共享的。

Demo

arguments.callee

我们可以利用 callee 引用来写几个常见的递归, 如下:

//求阶乘n! 即,1x2x3x4x5x......xn
function n(i){
  return i < 2 ? 1 : i*arguments.callee(i-1);
}
//求1+2+3......+n
function p(i){
  return i < 2 ? 1 : i+arguments.callee(i-1);
}
//斐波那契数列, 1,1,2,3,5,8,13,......
function f(i){
  var _f = arguments.callee;
  return i < 3 ? 1 : _f(i-1) + _f(i-2);
}
n(5);//120
p(5);//15
f(5);//5

遗憾的是: 严格模式(“use strict“)下, arguments.callee 并不可用.

arguments.length

js方法中形参个数并不能实际反映实参个数, 所幸的是 arguments.length 可以取得实参个数, 如下:

function a(a,b,c){
  console.log('实参个数:' + arguments.length);
}
a(1,2);//实参个数:2

arguments[]

这个共享其实不是真正的共享一个内存地址,而是2个不同的内存地址,使用JavaScript引擎来保证2个值是随时一样的,当然这也有一个前提, 那就是这个索引值要小于你传入的参数个数,也就是说如果你只传入2个参数,而还继续使用arguments[2]赋值的话,就会不一致(索引值从 0 开始),例如:

function b(x, y, z) {
    arguments[2] = 10;//参数可以被重新赋值
    console.log(z);
}
b(1, 2);//undefined

这时候因为没传递第三个参数z,所以赋值10以后,console.log(z)的结果依然是undefined,而不是10.

鸭式辩型

arguments 对象并不是一个真正的Array。它类似于数组,但没有数组所特有的属性和方法,除了 length。例如,它没有 pop 方法。不过可以将其转换成数组.

var args = Array.prototype.slice.call(arguments);//args为数组

像上面这中arguments虽然不是数组, 但我们把它当做数组处理, 这种现象叫做 鸭式辩型 .

如果一个对象可以像鸭子一样走路,游泳,并且嘎嘎叫,就认为这个对象是鸭子,哪怕它并不是从鸭子对象继承过来的。

在javascript里面,很多函数都不做对象的类型检测,而是只关心这些对象能做什么. 因此我们尽可利用鸭式辨型的便利, 以下就充分演示了把arguments当做一个数组来处理.

//合并参数
function myConcat(separator) {
  var args = Array.prototype.slice.call(arguments, 1);//相当于arguments调用了Array的slice方法
  return args.join(separator);
}
myConcat(", ", "red", "orange", "blue");//"red, orange, blue"

警告: 此处不应在 arguments 对象上使用 slice 方法,这会阻碍 JavaScript 引擎的优化 (比如 V8 引擎)。作为替代,应通过遍历 arguments 对象的方式来构建一个新的数组。更多信息

如果 Array generics 可用的话,下面的代码则可以作为替代:

var args = Array.slice(arguments);//注意,arguments对象仅在函数内部有效

本文就讨论这么多内容,大家有什么问题或好的想法欢迎在下方参与留言和评论.

本文作者: louis

本文链接: http://louiszhai.github.io/2015/12/15/arguments/

参考文章

Fork me on GitHub