网站首页 > 技术文章 正文
全文共5530字,预计学习时长11分钟
延展操作符首次于ES6中引入,并很快成为最受欢迎的功能之一。尽管事实上延展操作符只适用于数组,但仍有建议提出可以将其功能扩展到对象。最终ES9中引入了此功能。
本教程将说明为什么应该使用扩展运算符,以及它如何运作。
目录
1.为什么要使用延展操作符
2.克隆数组/对象
3.将类数组结构转换为数组
4.延展操作符作为参数
5.将元素添加到数组/对象
6.合并数组/对象
为什么要使用延展操作符
阅读了以上列表之后,你可能会想:“JavaScript就已经能够满足需求了,为什么还要使用延展操作符?”我们先来介绍下不变性。
牛津词典:不变性 - 随着时间的推移不变或无法改变。
作为软件开发的术语,不可变指状态不能随时间变化的值。实际上,通常使用的大多数值(原始值,如字符串,整数等)都是不可变的。
然而,JavaScript中非常特殊的一点是,其中的数组和对象实际上是可变的。这可能成为一个大问题。以下实例阐明了其中原因:
const mySquirtle={ name: 'Squirtle', type: 'Water', hp: 100 }; const anotherSquirtle = mySquirtle; anotherSquirtle.hp = 0; console.log(mySquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 0 }
从上述代码中可以看到,我们有一个变量Squirtle(杰尼龟)。因为刚刚访问了神奇宝贝中心,这只杰尼龟的HP值为100。
由于还想要另一只杰尼龟,因此声明变量为anotherSquirtle,将初始Squirtle指定为它的值。一场苦战后,另一只杰尼龟被击败了。因此,访问另一只杰尼龟的HP值并将其更改为0。下一步,检查初始Squirtle,输入console.log和...
等等,什么?初始Squirtle的HP降至0。这怎么可能?可怜的杰尼龟遭遇了什么?原来是发生了JavaScript变异。接下来将为你解释其中缘由。
当创建anotherSquirtle变量并将初始Squirtle指定为其值时,实际是给初始Squirtle对象的内存位置分配了一个引用。这是因为JavaScript数组和对象是引用数据类型。与基本数据类型不同,引用数据类型指向存储实际对象/数组的内存地址。
为了便于理解,可以将引用数据类型想象为全局变量的指针。更改引用数据类型的值实际上是在更改全局变量的值。
这意味着当将anotherSquirtle的HP值更改为0时,实际是将存储在内存中的Squirtle对象的HP值更改为0。这就是为什么mySquirtle的HP值为0 - 因为mySquirtle是对存储在内存中的对象的引用,可以通过anotherSquirtle变量被改变。谢谢JavaScript。
如何解决这个问题?
为了避免变量的变异,需要在要复制数组/对象时,创建数组/对象实例。如何实现这一操作?
使用延展操作符。
延展操作符如何运作
从MDN文档中可以查到:展开语法(spread syntax),可以在函数调用或数组构造时,将数组表达式或string等iterable在语法层面展开,还可以在构造字面量对象时,将对象表达式按键-值方式展开。
简而言之,延展操作符......延展iterable中的项(iterable指receiver中任何可循环的项,如字符串,数组,集等)。(receiver用于接收展开值。)为便于理解,以下是数组的简单示例:
const numbers = [1, 2, 3]; console.log(...numbers); //Result: 1 2 3 const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; console.log(...pokemon); //Squirtle Bulbasur Charmander const pokedex = [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }, { name: 'Charmander', type: 'Fire' } ]; console.log(...pokedex); //{ name: 'Squirtle', type: 'Water' } { name: 'Bulbasur', type: 'Plant' } { name: 'Charmander', type: 'Fire' } import pandas as pd
数组中使用延展操作符的三个示例
如上所示,当在数组上使用延展操作符时,可以获取数组中所含的每个单独的项。在上述所有示例中,receiver都是一个函数,即console.log函数。够简单吧?
克隆数组/对象
现在已经知道了延展操作符的工作原理,可以利用它复制数组和对象而不改变其值。怎么做呢?延展内容然后使用数组[]或对象文字{}来生成数组/对象实例。
仍然以上文的杰尼龟为例,通过克隆mySquirtle变量解决上文中的问题:
const mySquirtle = { name: 'Squirtle', type: 'Water', hp: 100 }; const anotherSquirtle = { ...mySquirtle }; anotherSquirtle.hp = 0; console.log(anotherSquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 0 } console.log(mySquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 100 }
使用延展操作符复制对象
通过使用解延展操作符解构mySquirtle变量内容并使用对象字面量,创建了Squirtle对象的新实例。这样,就防止变量突然变异。
使用相同的语法复制数组:
const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; const pokedex = [...pokemon]; pokedex.push('Cyndaquil'); console.log(pokemon); //[ 'Squirtle', 'Bulbasur', 'Charmander' ] console.log(pokedex); //[ 'Squirtle', 'Bulbasur', 'Charmander', 'Cyndaquil' ]
使用延展操作符复制数组
注意:延展操作符只执行浅拷贝。这意味着若在数组/对象中存储了引用数据类型,则在使用延展操作符进行复制时,嵌套数组/对象将包含对原始的引用,因此其数值将是可变的。
将类数组对象转换为数组
类数组对象与数组非常相似。它们通常都有编号元素和长度属性。但是,两者有一个至关重要的区别:类数组对象没有任何数组函数。
类数组对象包含主要由DOM方法返回的HTML节点列表,和每个JS函数和少部分其他函数自动生成的参数变量。
使用与克隆数组相同的语法,可以使用延展操作符将类数组结构转换为数组,这可以代替使用Array.from的方法。以下是将nodeList转换为数组的示例:
const nodeList = document.getElementsByClassName("pokemon"); const array = [...nodeList]; console.log(nodeList); //Result: HTMLCollection [ div.pokemon, div.pokemon ] console.log(array); //Result: Array [ div.pokemon, div.pokemon ]
将nodelist转换为数组
使用这种技术,可以将任何类数组结构转换为数组,从而访问所有数组函数。
延展操作符用作参数
某些函数接受可变数量的参数。其中一个典型列子就是Math集合中的函数。以Math.max()函数为例。它接受n个数字参数,并返回最大的参数。假设需要将一个数字数组传递给Math.max()函数。该怎么做呢?
可以这样做:
const numbers = [1, 4, 5]; const max = Math.max(numbers[0], numbers[1], numbers[2]); console.log(max); //Result: 5
但是,这样做无疑是自寻死路。若是有20个值怎么办?1000个值呢?真的要通过索引访问每个值吗?当然不是。我们可以通过使用延展操作符提取数组中每个单独的值,如下所示:
const numbers = [1, 4, 5, 6, 9, 2, 3, 4, 5, 6]; const max = Math.max(...numbers); console.log(max); //Result: 9
大救星:延展操作符。
添加新元素
将项添加到数组
向数组添加新元素,首先需要延展数组的内容并使用数字字面量[]创建数组实例,需要包含原始数组的内容以及要添加的值:
const pokemon = ['Squirtle', 'Bulbasur']; const charmander = 'Charmander'; const cyndaquil = 'Cyndaquil'; const pokedex = [...pokemon, charmander, cyndaquil]; console.log(pokedex); //Result: [ 'Squirtle', 'Bulbasur', 'Charmander', 'Cyndaquil' ]
使用延展操作符将项添加到数组中
如你所见,可以任意添加新项。
向对象添加属性
通过使用与数组相同的语法,可以在克隆对象时轻松添加新属性。稍微转变一下,就有一个不同的语法来向对象添加属性(也可以用于数组):
const basicSquirtle = { name: 'Squirtle', type: 'Water' }; const fullSquirtle = { ...basicSquirtle, species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }; console.log(fullSquirtle); //Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }
如你所见,可以在对象字面量中而不是在外部直接声明和初始化新变量。
合并数组/对象
数组
如上述例子所示,可以通过延展数组并使用数组字面量来合并两个数组。但是,这一部分要讲的不是简单地添加新元素,而是添加另一个(延展)数组:
const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; const morePokemon = ['Totodile', 'Chikorita', 'Cyndaquil']; const pokedex = [...pokemon, ...morePokemon]; console.log(pokedex); //Result: [ 'Squirtle', 'Bulbasur', 'Charmander', 'Totodile', 'Chikorita', 'Cyndaquil' ]
使用延展操作符合并数组
这也适用于数组对象:
const pokemon = [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }];const morePokemon = [{ name: 'Charmander', type: 'Fire' }]; const pokedex = [...pokemon, ...morePokemon]; console.log(pokedex); //Result: [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }, { name: 'Charmander', type: 'Fire' } ]Merging two arrays of objects with the spread operator
对象
可以使用与之前相同的语法将两个(或更多)对象合并到一个对象中(你可能已经留意到,扩展运算符在数组和对象中的使用方式非常相似):
const baseSquirtle = { name: 'Squirtle', type: 'Water' }; const squirtleDetails = { species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }; const squirtle = { ...baseSquirtle, ...squirtleDetails }; console.log(squirtle); //Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }
使用延展操作符合并对象
本教程说明了为什么应该使用扩展运算符(重点强调不变性!),它是如何工作的以及几个基本用法。
留言 点赞 关注
我们一起分享AI学习与发展的干货
如需转载,请后台留言,遵守转载规范
猜你喜欢
- 2024-11-10 趣谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64
- 2024-11-10 当裸辞遇到了面试难,你需要了解一下这些面试题
- 2024-11-10 JavaScript -- Map vs ForEach javascript map vs foreach
- 2024-11-10 面试官:请说下Object和Map的区别,Map的时间复杂度是多少
- 2024-11-10 JavaScript slice()方法用法简介 js中slice函数
- 2024-11-10 《你不知道的 Blob》番外篇 你不知道 小说
- 2024-11-10 js中检测数据类型的方法汇总 检测js对象是数组类型
- 2024-11-10 JS函数式编程工具:数组reduce方法的运用
- 2024-11-10 「前端知乎系列」ArrayBuffer 和 Blob 对象
- 2024-11-10 JavaScript 数组操作方法大全 js数组的用法
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-