arguments 对象
arguments 是一个类数组对象,包含函数调用时传入的所有参数,仅在普通函数中可用,箭头函数没有 arguments 对象。
#resource / javascript
#resource / ecmascript
#type / concept
#status / growing
[!info] related notes
- 所属 MOC: ecmascript-moc
- 前置概念: ecmascript-functions, this-keyword
- 相关概念: rest-parameters-and-spread-operator, function-length
- 对比概念: rest-parameters-and-spread-operator
arguments 对象
一句话定义
arguments 是一个类数组对象,包含函数调用时传入的所有参数,仅在普通函数中可用,箭头函数没有 arguments 对象。
核心机制
基本行为
function fn(a, b, c) {
console.log(arguments.length); // 3
console.log(arguments[0]); // 1
console.log(arguments[1]); // 2
console.log(arguments[2]); // 3
}
fn(1, 2, 3);
关键特性
- 类数组对象:有
length属性,可以通过索引访问,但不是真正的数组 - 仅普通函数可用:箭头函数没有
arguments - 包含所有参数:包括超出形参数量的参数
- 与形参同步:在非严格模式下,
arguments和形参是同步的
arguments 与命名参数的绑定关系
arguments 可以理解为函数执行时创建的一个”静态数组快照”,但它和命名参数之间存在双向同步(非严格模式下)。
已传递的参数:双向同步
function log(a, b, c, d) {
console.log(a, b, c, d); // 1, 2, 3, undefined
arguments[0] = 'bfe';
console.log(a, b, c, d); // "bfe", 2, 3, undefined
a = 'changed';
console.log(arguments[0]); // "changed"
}
log(1, 2, 3);
arguments[0] 和 a 指向同一个绑定,改一个另一个跟着变。
未传递的参数:不同步
function log(a, b, c, d) {
arguments[3] = 'dev';
console.log(d); // undefined(没变)
console.log(arguments[3]); // "dev"(只改了 arguments 自身)
}
log(1, 2, 3);
调用时只传了 3 个参数,arguments 内部只有 3 个元素。给 arguments[3] 赋值只是在 arguments 对象上新增了一个属性,不会同步到 d,因为 d 在 arguments 中没有对应的槽位。
总结规律
| 操作 | 效果 |
|---|---|
修改 arguments[n],n < 实际传参个数 | 同步修改对应的命名参数 |
修改 arguments[n],n >= 实际传参个数 | 只在 arguments 对象上操作,不影响命名参数 |
| 修改命名参数,n < 实际传参个数 | 同步修改对应的 arguments[n] |
| 修改命名参数,n >= 实际传参个数 | 不影响 arguments |
详细示例
1. 基本使用
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15
2. 转换为真正的数组
function fn() {
// 方法 1:Array.from()
const arr1 = Array.from(arguments);
// 方法 2:展开运算符
const arr2 = [...arguments];
// 方法 3:slice
const arr3 = Array.prototype.slice.call(arguments);
// 方法 4:apply
const arr4 = [].slice.apply(arguments);
}
3. 严格模式下的行为
'use strict';
function fn(a, b) {
a = 10;
console.log(arguments[0]); // 1(不同步)
console.log(a); // 10
}
fn(1, 2);
与 rest 参数的区别
| 特性 | arguments | rest 参数 |
|---|---|---|
| 类型 | 类数组对象 | 真正的数组 |
| 可用性 | 仅普通函数 | 所有函数(包括箭头函数) |
| 包含内容 | 所有参数 | 只包含剩余参数 |
| 数组方法 | 需要转换 | 直接可用 |
| 严格模式 | 不与形参同步 | 不受影响 |
// arguments:类数组对象
function sumArgs() {
// console.log(arguments.reduce); // undefined
return Array.from(arguments).reduce((a, b) => a + b, 0);
}
// rest 参数:真正的数组
function sumRest(...args) {
// console.log(args.reduce); // function
return args.reduce((a, b) => a + b, 0);
}
// 箭头函数只能用 rest 参数
const sumArrow = (...args) => args.reduce((a, b) => a + b, 0);
实际应用
1. 可变参数函数
function log(...args) {
console.log('[LOG]', ...args);
}
log('User', 'logged', 'in');
// [LOG] User logged in
2. 参数转发
function wrapper() {
// 将所有参数转发给另一个函数
return actualFunction.apply(this, arguments);
}
3. 函数重载模拟
function add() {
if (arguments.length === 2) {
return arguments[0] + arguments[1];
} else if (arguments.length === 3) {
return arguments[0] + arguments[1] + arguments[2];
}
throw new Error('Invalid number of arguments');
}
add(1, 2); // 3
add(1, 2, 3); // 6
常见误解
1. 箭头函数没有 arguments
const arrowFn = () => {
// console.log(arguments); // ReferenceError: arguments is not defined
};
// 箭头函数可以使用外层函数的 arguments
function outer() {
const inner = () => {
console.log(arguments[0]); // 可以访问 outer 的 arguments
};
inner();
}
outer(1); // 1
2. arguments 不是数组
function fn() {
console.log(Array.isArray(arguments)); // false
// 需要转换才能使用数组方法
const arr = Array.from(arguments);
console.log(Array.isArray(arr)); // true
}
3. 严格模式下的同步问题
'use strict';
function fn(a) {
a = 100;
console.log(arguments[0]); // 1(不同步)
}
fn(1);
现代替代方案
推荐使用 rest 参数
// ❌ 旧方式:使用 arguments
function sum() {
return Array.from(arguments).reduce((a, b) => a + b, 0);
}
// ✅ 新方式:使用 rest 参数
function sum(...args) {
return args.reduce((a, b) => a + b, 0);
}
何时仍需使用 arguments
- 兼容旧代码:旧浏览器可能不支持 rest 参数
- 需要访问调用者信息:
arguments.callee(严格模式不可用) - 与现有 API 交互:某些旧 API 可能依赖
arguments
BFE.dev 相关题目
- 19. this:理解函数调用时的参数传递
- 33. this II:理解 arguments 和 this 的关系
面试要点
- 类数组对象:知道 arguments 不是真正的数组
- 箭头函数限制:箭头函数没有 arguments
- 严格模式:严格模式下 arguments 不与形参同步
- 现代替代:推荐使用 rest 参数替代 arguments
- 转换方法:知道如何将 arguments 转换为数组