rest 参数和 spread 运算符

rest 参数(...args)用于收集多个参数为数组,spread 运算符(...arr)用于将数组展开为独立参数,两者语法相同但用途相反。

#resource / javascript #resource / ecmascript #type / concept #status / evergreen

[!info] related notes

rest 参数和 spread 运算符

一句话定义

... 运算符有两种用途:rest 参数用于函数定义时收集多个参数为数组,spread 运算符用于函数调用或数组/对象字面量中将数组展开为独立元素。

核心机制

Rest 参数(剩余参数)

用于函数定义时,将剩余的参数收集到一个数组中:

function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}

sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15

Spread 运算符(展开运算符)

用于函数调用或数组/对象字面量中,将数组/对象展开为独立的元素:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// 数组合并
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// 函数调用
function add(a, b, c) {
  return a + b + c;
}
add(...arr1); // 6

// 对象合并
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const mergedObj = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }

详细对比

特性Rest 参数Spread 运算符
位置函数定义的参数列表函数调用、数组/对象字面量
用途收集多个参数为数组展开数组/对象为独立元素
语法function fn(...args)fn(...args)[...arr]
结果创建新数组不创建新数组,只是展开

实际应用

1. 参数处理

// Rest 参数:收集剩余参数
function logFirst(first, ...rest) {
  console.log('第一个参数:', first);
  console.log('剩余参数:', rest);
}

logFirst(1, 2, 3, 4); 
// 第一个参数: 1
// 剩余参数: [2, 3, 4]

2. 数组操作

// Spread:复制数组
const original = [1, 2, 3];
const copy = [...original];

// Spread:合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4]

// Spread:在数组中插入元素
const arr = [1, 2, 3];
const newArr = [0, ...arr, 4]; // [0, 1, 2, 3, 4]

3. 函数调用

// Spread:将数组作为参数传递
function add(a, b, c) {
  return a + b + c;
}

const numbers = [1, 2, 3];
add(...numbers); // 6

// 等价于
add(1, 2, 3); // 6

4. 对象操作

// Spread:复制对象
const original = { a: 1, b: 2 };
const copy = { ...original };

// Spread:合并对象
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 3, c: 4 }

// Spread:更新对象属性
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 }; // { name: 'Alice', age: 26 }

与 arguments 对象的区别

Rest 参数的优势

  1. 是真正的数组:可以直接使用数组方法
  2. 箭头函数可用:箭头函数没有 arguments,但可以使用 rest 参数
  3. 更清晰:明确表示”剩余参数”
// 使用 arguments(类数组对象)
function sumArgs() {
  return Array.from(arguments).reduce((a, b) => a + b, 0);
}

// 使用 rest 参数(真正的数组)
function sumRest(...args) {
  return args.reduce((a, b) => a + b, 0);
}

// 箭头函数只能用 rest 参数
const sumArrow = (...args) => args.reduce((a, b) => a + b, 0);

何时使用哪个

场景推荐原因
现代代码Rest 参数更清晰、是真正的数组
需要 this 绑定Rest 参数箭头函数配合 rest 参数
兼容旧代码arguments旧浏览器可能不支持 rest 参数

常见误解

1. Rest 参数必须是最后一个参数

// ❌ 错误:rest 参数后面不能有其他参数
function fn(...args, last) {} // SyntaxError

// ✅ 正确:rest 参数必须是最后一个
function fn(first, ...rest) {}

2. 函数 length 属性不包括 rest 参数

function fn(a, b, ...rest) {}
console.log(fn.length); // 2,不包括 rest 参数

3. Spread 不限于数组

// 字符串展开
const str = 'hello';
const chars = [...str]; // ['h', 'e', 'l', 'l', 'o']

// NodeList 展开
const divs = document.querySelectorAll('div');
const divArray = [...divs];

BFE.dev 相关题目

  • 1. implement curry():使用 spread 运算符合并参数
  • 19. this:理解函数调用时的参数传递

面试要点

  1. 语法区别:知道 rest 参数用于定义,spread 用于调用/展开
  2. 数组特性:rest 参数是真正的数组,不是类数组对象
  3. 位置限制:rest 参数必须是最后一个参数
  4. length 属性:rest 参数不计入函数的 length 属性
  5. 箭头函数:箭头函数可以使用 rest 参数,但不能使用 arguments

信息参考

创建于 2026/3/31 更新于 2026/5/27