JavaScript arguments 对象全面介绍

2023-02-03 0 1,146

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

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. arguments – JavaScript

3. Avoid modifying or passing `arguments` into other functions

4. Optimization killers · petkaantonov/bluebird Wiki · GitHub

5. Why isnt a functions 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?

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务