多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 什么是arguments **「`arguments`」**是一个对应于传递给函数的参数的类数组对象。这是MDN上给出的解释,我们仔细看这个解释,可以圈出这个解释的关键字就是`类数组对象`,类数组其实并不是数组对象,只是相似,我们通过下面的简单例子可以更好的理解。 ~~~ function printArgs() {   console.log(arguments) } printArgs('herry', 'lee', { name: 'herry lee' })  ~~~ 执行结果: ![](https://img.kancloud.cn/6b/7b/6b7bc76cdfebe3d7641d0e58adf10ee0_574x166.png) ~~~ ["herry","lee",Object] ~~~ 从输出结果我们可以看到这并不是真正的数据,只是和数组很像而已。而且我们从上图可以更直观的看出可以通过`arguments[0]`,`arguments[1]`来获取相对应的传入参数。 ## arguments操作 ### arguments.length 我们已经知道 arguments是一个类数组对象,包含了一个`length`属性,因此可以用`arguments.length`来获取传入参数的长度,这一点在我们平时写代码中用处很多。 ### arguments转数组 有两种方法可以讲arguments转换成数组,其实原理是一样的。 ~~~ Array.prototype.slice.call(arguments) [].slice.call(arguments) ~~~ 主要是使用了call,具体可以参考我上一篇文章,这里就不做过多的解释了。 ### 修改arguments的值 在严格模式与非严格模式下,修改函数参数值表现的结果不一样。看下面的两个例子: ~~~ function foo(a) {     "use strict";     console.log(a, arguments[0]);     a = 10;     console.log(a, arguments[0]);     arguments[0] = 20;     console.log(a, arguments[0]); } foo(1); ~~~ 输出: ~~~ 1 1 10 1 10 20 ~~~ 另一个非严格模式的例子: ~~~ function foo(a) {     console.log(a, arguments[0]);     a = 10;     console.log(a, arguments[0]);     arguments[0] = 20;     console.log(a, arguments[0]); } foo(1); ~~~ 输出结果为: ~~~ 1 1 10 10 20 20 ~~~ 从上面的两个例子中可以看出,在严格模式下,函数中的参数与 arguments 对象没有联系,修改一个值不会改变另一个值。而在非严格模式下,两个会互相影响。 ### 将参数从一个函数传递到另一个函数 下面是将参数从一个函数传递到另一个函数的推荐做法。 ~~~ function foo() {     bar.apply(this, arguments); } function bar(a, b, c) {     // logic } ~~~ ### arguments与重载 我们知道在JavaScript这个语言中,是不存在重载的,但是我们可以通过arguments实现重载,首先我们要看一下什么是重载。 ~~~ function add(num1, num2) {     console.log(1); } function add(num1, num2, num3) {     console.log(2); } add(1, 2); //2 add(1, 2, 3);//2 ~~~ 所以,JavaScript 中,函数并没有根据参数的不同而产生不同的调用。 所以,JavaScript 中,函数并没有根据参数的不同而产生不同的调用。 是不是 JavaScript 中就没有重载了呢?并不是,我们可以利用 arguments 模拟重载。还是上面的例子。 ~~~ function add(num1, num2, num3) {     if (arguments.length === 2) {         console.log("Result is " + (num1 + num2));     }     else if (arguments.length === 3) {         console.log("Result is " + (num1 + num2 + num3));     } } add(1, 2); add(1, 2, 3) ~~~ 执行结果如下: ~~~ Result is 3 Result is 6 ~~~ ## ES6 中的 arguments ### 扩展操作符 直接上栗子: ~~~ function func() {     console.log(...arguments); } func(1, 2, 3); ~~~ 执行结果是: ~~~ 1 2 3 ~~~ 简洁地讲,扩展操作符可以将 arguments 展开成独立的参数。 ### Rest 参数 还是上栗子: ~~~ function func(firstArg, ...restArgs) {     console.log(Array.isArray(restArgs));     console.log(firstArg, restArgs); }   func(1, 2, 3); ~~~ 执行结果是: ~~~ true 1 [2, 3] ~~~ 从上面的结果可以看出,Rest 参数表示除了明确指定剩下的参数集合,类型是 Array。 默认参数 栗子: ~~~ function func(firstArg = 0, secondArg = 1) {     console.log(arguments[0], arguments[1]);     console.log(firstArg, secondArg); } func(99); ~~~ 执行结果是: ~~~ 99 undefined 99 1 ~~~ 可见,默认参数对 arguments 没有影响,arguments 还是仅仅表示调用函数时所传入的所有参数。 ### arguments 转数组 `Array.from()`是个非常推荐的方法,其可以将所有类数组对象转换成数组。 ## 数组与类数组对象 数组具有一个基本特征:索引。这是一般对象所没有的。 ~~~ const obj = { 0: "a", 1: "b" }; const arr = [ "a", "b" ]; ~~~ 我们利用`obj[0]`、`arr[0]`都能取得自己想要的数据,但取得数据的方式确实不同的。`obj[0]`是利用对象的键值对存取数据,而`arr[0]`却是利用数组的索引。事实上,Object 与 Array 的唯一区别就是 Object 的属性是 string,而 Array 的索引是 number。 下面看看类数组对象。 伪数组的特性就是长得像数组,包含一组数据以及拥有一个 length 属性,但是没有任何 Array 的方法。再具体的说,length 属性是个非负整数,上限是 JavaScript 中能精确表达的最大数字;另外,类数组对象的 length 值无法自动改变。 如何自己创建一个类数组对象? ~~~ function Foo() {} Foo.prototype = Object.create(Array.prototype); const foo = new Foo(); foo.push('A'); console.log(foo, foo.length); console.log("foo is an array? " + Array.isArray(foo)); ~~~ 执行结果是: ~~~ ["A"] 1 foo is an array? false ~~~ 也就是说 Foo 的实例拥有 Array 的所有方法,但类型不是 Array。 如果不需要 Array 的所有方法,只需要部分怎么办呢? ~~~ function Bar() {} Bar.prototype.push = Array.prototype.push; const bar = new Bar(); bar.push('A'); bar.push('B'); console.log(bar); ~~~ 执行结果是: ~~~ Bar {0: "A", 1: "B", length: 2} ~~~