一篇文章帮你彻底搞懂扩展运算符

什么是扩展运算符号?

扩展运算符是一种操作符,它可以将我们可迭代对象扩展为单独的元素。常用于在函数调用、数组构造、构造字面量对象等情况下,将数组、类数组对象或字符串展开为单独的元素,或将对象展开为键值对。在语法层面展开数据

扩展运算符特性

  • 扩展运算符允许在其后接受表达式。
  • 在数组或函数参数中使用展开语法(...)时,该语法只能用来将可迭代对象(即部署了 Iterator 遍历器接口的对象)的数组表达式或字符串在语法层面进行展开操作。
  • 扩展运算符可用于展开/合并数组,将类数组对象转换为数组,并且可以用于接收参数。
  • 扩展运算符仅执行浅拷贝,这意味着它只会复制对象的引用,而不是对象本身的内容。
  • 在使用扩展运算符时,需要记住扩展运算符并不会克隆相同的属性

结合代码进行说明

扩展运算符允许在其后接受表达式

js 复制代码
// 设定变量 x 的值为 10
const x = 10;

// 构造数组 arr
const arr = [
  // 判断 x 是否大于 0,如果是则返回包含 'a' 的数组,否则返回空数组,然后使用扩展运算符将其展开
  ...(x > 0 ? ['a'] : []),
  // 将 'b' 加入数组 arr
  'b',
];

// 构造对象 obj
const obj = {
  // 判断 x 是否大于 1,如果是则返回包含属性 'a' 的对象,否则返回空对象,然后使用扩展运算符将其展开
  ...(x > 1 ? { a: 1 } : {}),
  // 添加属性 'b',值为 2
  b: 2,
};

// 输出数组 arr
console.log(arr); // ["a", "b"]

// 输出对象 obj
console.log(obj); // { a: 1, b: 2 }

扩展运算符可用于展开/合并数组,将类数组对象转换为数组,并且可以用于接收参数。

使用运算符展开数组
js 复制代码
const array1 = [1, 2, 3];
const array2 = [4, 5, ...array1, 6];

console.log(array2); // 输出:[4, 5, 1, 2, 3, 6]
使用运算符合并数组

示例一

js 复制代码
const coffee = ['coffee', 'water'];
const spices = ['cinnamon', 'nutmeg', 'cardamom'];

const coffeeReady = [...coffee, ...spices];

console.log(coffeeReady) 
// 输出:['coffee', 'water', 'cinnamon', 'nutmeg', 'cardamom'];

示例二

js 复制代码
const mySiblings = { 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
};

const myFamily = { 
  fathersName: 'Michael', 
  mothersName: 'Louise',
  ...mySiblings
};
// Now we can treat brothersName and sistersName as 
// a property of myFamily:
console.log(myFamily.brothersName) 
将类数组对象转换为数组
js 复制代码
// 类数组对象
const arrayLikeObject = { 0: 'a', 1: 'b', 2: 'c', length: 3 };

// 将类数组对象转换为数组
const array = [...arrayLikeObject];

console.log(array); // 输出:['a', 'b', 'c']

将字符串转换成数组

js 复制代码
const str = 'coffee';
const letters = [...str, 's.', '☕️']; 
console.log(letters);// ["c", "o", "f", "f", "e", "e", "s.", "☕️"]
使用运算符接收参数
js 复制代码
function myFunction(x, y, z) {
  console.log(x, y, z);
}

const args = [1, 2, 3];
myFunction(...args); // 输出:1 2 3

扩展运算符并不会克隆相同的属性

在下面的例子中,我们的vegetable1对象和vegetable2对象里都有一个相同的属性potato,但是跳转的值不同,在使用扩展运算符时,它并不会克隆相同的属性,而是会将后面对象中的属性值覆盖前面对象中的属性值。

js 复制代码
const vegetable1 = { 
  potato: '土豆', 
  tomato: '番茄',
  cucumber: '青瓜'
};
const vegetable2 = { 
  potato: '马铃薯', 
  cucumber: '黄瓜', 
  pumpkin: '南瓜', 
};

const allVegetable = { ...vegetable1, ...vegetable2 };
console.log(allVegetable);
/* 输出
{ 
  tomato: '番茄',
  cucumber: '青瓜'
  potato: '马铃薯', 
  cucumber: '黄瓜', 
  pumpkin: '南瓜', 
}
*/

扩展运算符仅执行浅拷贝

js 复制代码
let a = [1, [2, 3]]; // 定义数组 a,其中包含一个嵌套的数组 [2, 3]
const b = [4, 5, 6];

let c = [...a, ...b]; // 将数组 a 和数组 b 展开,并将它们的元素合并到数组 c 中
console.log(c);
// 输出: [1, [2, 3], 4, 5, 6]

a[0] = 11; // 修改数组 a 的第一个元素为 11
a[1][0] = 22; // 修改数组 a 中嵌套数组的第一个元素为 22

console.log(c);
// 输出: [1, [22, 3], 4, 5, 6]
  • 在上面的代码中,当我们使用扩展运算符 ... 将数组 a 和数组 b 展开到数组 c 中时,c 中的 [2, 3] 实际上是对数组 a 中嵌套数组的引用。因此,c 中的第二个元素 [2, 3] 并不是复制了数组 a 中的 [2, 3],而是引用了相同的嵌套数组。
  • 当我们修改数组 a 中的元素时,由于 c 中的嵌套数组和数组 a 中的嵌套数组是同一个引用,所以 c 中的嵌套数组也会被修改。
  • 因此,尽管我们只修改了数组 a,但数组 c 也受到了影响,其中嵌套数组的元素被修改为了 [22, 3]

注意:浅拷贝只能复制对象或数组的顶层结构。如果原始对象或数组中包含嵌套的对象或数组,浅拷贝后的对象或数组仍然会与原始对象或数组共享相同的嵌套对象或数组。这意味着在浅拷贝中修改嵌套对象或数组会影响到所有相关的对象或数组。

讲到这里肯定很多人会一想到,Object.assign(),它同样也能将另一个对象里的值拷贝到目标对象中,那他们之间有什么区别呢?

Object.assign() 和扩展运算的区别
特性 扩展运算符 (...) Object.assign()
语法 更简洁,直观 语法稍微复杂,接受目标对象和一个或多个源对象作为参数
返回值 返回一个新的对象或数组,其中包含了源对象或数组的属性或元素 返回目标对象本身,并且修改后的对象会直接反映在目标对象上
用途 用于对象和数组的浅拷贝,以及数组的合并 用于将一个或多个源对象的属性复制到目标对象中,也可以用于对象的浅拷贝和属性的合并
处理非对象类型 仅能处理对象和数组 能处理非对象类型的值,如字符串、数字、布尔值等,并将它们包装成对象
属性的设置方式 忽略源对象中的非自身可枚举属性 复制所有可枚举属性,包括原型链上的属性
相关推荐
gqkmiss34 分钟前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
bryant_meng1 小时前
【python】OpenCV—Image Moments
开发语言·python·opencv·moments·图片矩
若亦_Royi1 小时前
C++ 的大括号的用法合集
开发语言·c++
资源补给站2 小时前
大恒相机开发(2)—Python软触发调用采集图像
开发语言·python·数码相机
m0_748247553 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
6.943 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala
m0_748255023 小时前
前端常用算法集合
前端·算法
FF在路上3 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203984 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui