目录

🚅 JavaScript Rest 参数与 Spread 语法

# Rest 参数

Rest 参数可以通过使用三个点 ... 并在后面跟着包含剩余参数的数组名称,来将它们包含在函数定义中。这些点的字面意思是「将剩余参数收集到一个数组中」。

🌰 例子:

function sumAll(...args) { 
  let sum = 0;

  for (let arg of args) sum += arg;

  return sum;
}

console.log(sumAll(1, 2, 3, 4, 5, 6))
1
2
3
4
5
6
7
8
9

🌰 例子 / 有其他参数 :

function showName(firstName, lastName, ...titles) {
  console.log( firstName + ' ' + lastName )
  
  console.log(titles[0])
  console.log(titles[1])
  console.log(titles.length)
}

showName("Julius", "Caesar", "Consul", "Imperator");
1
2
3
4
5
6
7
8
9

注意

Rest 参数必须放到参数列表的末尾

❌ 例如 / 错误示范:

function f(arg1, ...rest, arg2) { // arg2 在 ...rest 后面?!
  // error
}
1
2
3

# arguments 变量

arguments 是一个特殊的类数组对象,按参数索引包含所有参数。

🌰 例子 :

function showName() {
  console.log( arguments.length );
  console.log( arguments[0] );
  console.log( arguments[1] );

}
1
2
3
4
5
6

以前的 JavaScript 中没有 Rest 参数,而使用 arguments 是获取函数所有参数的唯一方法。

但缺点是,尽管 arguments 是一个 类数组,也是可迭代对象,但它终究不是数组。它不支持数组方法,因此我们不能调用 arguments.map(...) 等方法。此外,它始终包含所有参数,不能截取入参的一部分使用。

所以实际开发最好使用 ... Rest 参数。

注意

箭头函数中没有 arguments 。访问到的 arguments 并不属于箭头函数,而是属于箭头函数外部的 “普通” 函数。

类似箭头函数没有自身的 this

# Spread 语法

与 Rest 参数需要接收多个参数相反,这里使用 ... 传递多个参数(可迭代对象)

🌰 例子 / 以 Math.max() 为例,返回传入的参数中的最大值,但是不能传入一个 数组, Math.max() 要传入一个列表形式的数值型参数。

let arr = [3, 5, 1];
console.log(Math.max(arr)); // error
1
2

显然不可能手动取 [] 数组的每一个元素,因为有可能不确定数组的元素数量。因此,可以使用 Spread 语法 :

console.log(Math.max(...arr))
1

🌰 例子 / 可以传递多个 可迭代对象

console.log(Math.max(...arr1, ...arr2))
1

🌰 例子 / 可以是任何的可迭代对象,包括字符串,将字符串转换为字符数组:

let str = 'Hello'
console.log([...str])
1
2

Spread 语法内部使用了 迭代器 来收集元素,与 for..of 的方式相同。因此,对于一个字符串, for..of 会逐个返回该字符串中的字符, ...str 也同理会得到 "H","e","l","l","o" 这样的结果。随后,字符列表被传递给数组初始化器 [...str]

使用 Array.from(str)

let str = 'Hello'
console.log(Array.from(str))
1
2

Array.from(obj)[...obj] 存在一个细微的差别:

  • Array.from 适用于 类数组对象 也适用于 可迭代对象
  • Spread 语法只适用于 可迭代对象

所以 Array.from() 更加通用。

# 复制对象 / 数组

⌛️ JavaScript 对象的复制与引用 中,使用 Object.assign() 进行对象的浅拷贝。此处使用 Spread 语法能实现同样的效果。

🌰 例子 / 复制数组:

let arr = [1, 2, 3]

let arrCopy = [...arr]

// 检查两个数组的内容是否相同
console.log(JSON.stringify(arr) === JSON.stringify(arrCopy)) // true
// 检查两个数组的引用是否相同
console.log(arr === arrCopy) // false
1
2
3
4
5
6
7
8
arr.push(4) // 修改原数组
console.log(arr.copy) // 副本对象不受影响
1
2

🌰 例子 / 复制对象:

let obj = { a: 1, b: 2, c: 3 };

let objCopy = { ...obj };

// 检查两个对象的内容是否相同
console.log(JSON.stringify(obj) === JSON.stringify(objCopy));

// 检查两个对象的引用是否相同
console.log(obj === objCopy); 

obj.d = 4 // 修改原对象
console.log(objCopy) // 副本对象不受影响
1
2
3
4
5
6
7
8
9
10
11
12

# 总结

  • ... 的使用不是 Rest 参数,就是 Spread 语法。

    • ... 出现在 函数参数列表的最后,那么它就是 Rest 参数,它会把参数列表中剩余的参数收集到一个数组中。
    • ... 出现在 函数调用或类似的表达式 中,那它就是 Spread 语法,它会把一个数组展开为列表
  • 使用场景的不同:

    • Rest 参数用于创建可接受任意数量参数的函数。
    • Spread 语法用于将数组传递给通常需要含有许多参数的列表的函数。

这两种方法的使用可以轻松的 转换数组为参数列表、数组和对象传递。

📢 上次更新: 2022/09/02, 10:18:16