JavaScript arguments 对象周全引见

1. 什么是 arguments

MDN 上诠释:

arguments 是一个类数组对象。代表传给一个function的参数列表。

我们先用一个例子直观相识下 JavaScript 中的 arguments 长什么模样。

function printArgs() {
    console.log(arguments);
}

printArgs("A", "a", 0, { foo: "Hello, arguments" });

实行效果是:

["A", "a", 0, Object]

乍一看,效果是个数组,但并非真正的数组,所以说 arguments 是一个类数组的对象(想相识真正数组与类数组对象的区分能够一向翻到末了)。

再看看 arguments 示意的内容,其示意了函数实行时传入函数的一切参数。在上面的例子中,代表了传入 printArgs 函数中的四个参数,能够分别用 arguments[0]arguments[1]… 来猎取单个的参数。

2. arguments 操纵

2.1 arguments length

arguments 是个类数组对象,其包括一个 length 属性,能够用 arguments.length 来获得传入函数的参数个数。

function func() {
    console.log("The number of parameters is " + arguments.length);
}

func();
func(1, 2);
func(1, 2, 3);

实行效果以下:

The number of parameters is 0
The number of parameters is 2
The number of parameters is 3

2.2 arguments 转数组

平常运用下面的要领来将 arguments 转换成数组:

Array.prototype.slice.call(arguments);

另有一个更简短的写法:

[].slice.call(arguments);

在这里,只是简朴地挪用了空数组的 slice 要领,而没有从 Array 的原型层面挪用。

为何上面两种要领能够转换呢?

起首,slice 要领获得的效果是一个数组,参数就是 arguments。事实上,满足肯定前提的对象都能被 slice 要领转换成数组。看个例子:

const obj = { 0: "A", 1: "B", length: 2 };
const result = [].slice.call(obj);
console.log(Array.isArray(result), result);

实行效果是:

true ["A", "B"]

从上面例子能够看出,前提就是: 1) 属性为 0,1,2…;2) 具有 length 属性;

别的,有一个须要注重的处所就是,不能将函数的 arguments 泄漏或许通报出去。什么意思呢?看下面的几个泄漏 arguments 的例子:

// Leaking arguments example1:
function getArgs() {
    return arguments;
}

// Leaking arguments example2:
function getArgs() {
    const args = [].slice.call(arguments);
    return args;
}

// Leaking arguments example3:
function getArgs() {
    const args = arguments;
    return function() {
        return args;
    };
}

上面的做法就直接将函数的 arguments 对象泄漏出去了,终究的效果就是 V8 引擎将会跳过优化,致使相当大的机能丧失。

你能够这么做:

function getArgs() {
    const args = new Array(arguments.length);
    for(let i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

那就很猎奇了,我们每次运用 arguments 时平常第一步都邑将其转换为数组,同时 arguments 运用不当还轻易致使机能丧失,那末为何不将 arguments 直接设想成数组对象呢?

这须要从这门言语的一开始提及。arguments 在言语的初期就引入了,当时的 Array 对象具有 4 个要领: toString、 join、 reverse 和 sort。arguments 继续于 Object 的很大原因是不须要这四个要领。而如今,Array 添加了许多壮大的要领,比方 forEach、map、filter 等等。那为何如今不在新的版本里让 arguments 从新继续自 Array呢?实在 ES5 的草案中就包括这一点,但为了向前兼容,终究照样被委员会反对了。

2.3 修正 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 对象没有联络,修正一个值不会转变另一个值。而在非严厉形式下,两个会相互影响。

2.4 将参数从一个函数通报到另一个函数

下面是将参数从一个函数通报到另一个函数的引荐做法。

function foo() {
    bar.apply(this, arguments);
}
function bar(a, b, c) {
    // logic
}

2.5 arguments 与重载

许多言语中都有重载,但 JavaScript 中没有。先看个例子:

function add(num1, num2) {
    console.log("Method one");
    return num1 + num2;
}

function add(num1, num2, num3) {
    console.log("Method two");
    return num1 + num2 + num3;
}

add(1, 2);
add(1, 2, 3);

实行效果为:

Method two
Method two

所以,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

3. ES6 中的 arguments

3.1 扩大操纵符

直接上栗子:

function func() {
    console.log(...arguments);
}

func(1, 2, 3);

实行效果是:

1 2 3

简约地讲,扩大操纵符能够将 arguments 展开成自力的参数。

3.2 Rest 参数

照样上栗子:

function func(firstArg, ...restArgs) {
    console.log(Array.isArray(restArgs));
    console.log(firstArg, restArgs);
}

func(1, 2, 3);

实行效果是:

true
1 [2, 3]

从上面的效果能够看出,Rest 参数示意除了明白指定剩下的参数鸠合,范例是 Array。

3.3 默许参数

栗子:

function func(firstArg = 0, secondArg = 1) {
    console.log(arguments[0], arguments[1]);
    console.log(firstArg, secondArg);
}

func(99);

实行效果是:

99 undefined
99 1

可见,默许参数对 arguments 没有影响,arguments 照样仅仅示意挪用函数时所传入的一切参数。

3.4 arguments 转数组

Array.from() 是个异常引荐的要领,其能够将一切类数组对象转换成数组。

4. 数组与类数组对象

数组具有一个基本特征:索引。这是平常对象所没有的。

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}

参考:

  1. JavaScript中的数组与伪数组的区分

  2. MDN arguments

  3. Avoid modifying or passing arguments into other functions — it kills optimization

  4. Optimization killers

  5. Why isn’t a function’s arguments object an array in Javascript?

  6. arguments 对象

  7. Advanced Javascript: Objects, Arrays, and Array-Like objects

  8. JavaScript 特别对象 Array-Like Objects 详解

  9. What is a good way create a Javascript array-like object?

    原文作者:CompileYouth
    原文地址: https://segmentfault.com/a/1190000007091243
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞