JavaScript 每日一篇,记录自学JavaScript语言的点点滴滴。
MDN 官网上对于JavaScript展开语法的解释:
developer.mozilla.org/zh-CN/docs/...
在ES6版的JavaScript发布之前,要想在数组内增加元素,或将两个数组合并;我们必须具体声明数组元素的内容和索引。
ini
const arr = [7, 8, 9];
const badNewArr = [1, 2, arr[0], arr[1], arr[2]];
console.log('badNewArr: ', badNewArr);
通过展开语法...
将两个数组的元素进行合并
现在如果想让arr
数组和newArr
数组进行合并,你只需在需要合并的数组前加上...
即可将两个数组合并成一个数组并赋值给newArr
。
ini
const arr = [7, 8, 9];
const newArr = [1, 2, ...arr];
console.log('newArr: ', newArr);
通过这种方式合并两个数组的内容不仅可以降低数组元素引用的错误,还可以提高代码的可读性。
其次,如果你好奇想查看一下...newArr
输出了什么结果,你会惊奇的发现,...newArr
和console.log(1, 2, 7, 8, 9);
都输出的形式一样,两者在内存中实际上是同一种数据类型。
ini
let a = console.log(...newArr);
let b = console.log(1, 2, 7, 8, 9);
console.log(a === b);
当然这种数组展开语法方式也可以应用到对象数组上,通过浅拷贝创建一个数组的副本。
arduino
const restaurant = {
name: '意大利🇮🇹经典',
location: 'Via Angelo Tavanti 23, 佛罗伦萨, 意大利',
categories: ['意大利', '比萨店', '素食', '有机'],
starterMenu: ['佛卡夏', '意式烤面包', '大蒜面包', '卡普雷塞沙'],
mainMenu: ['披萨', '意大利面', '烩饭'],
};
const newMenu = [...restaurant.mainMenu, '汤圆Gnocci'];
console.log(newMenu);
通过数组展开语法...
复制一个和restaurant
对象下的mainMenu
属性内相同的数组。
arduino
// 通过浅拷贝创建一个数组
const mainMenuCopy = [...restaurant.mainMenu];
console.log('mainMenuCopy: ', mainMenuCopy);
连接🔗两个数组:
arduino
// 🔗连接两个数组
console.log('restaurant.mainMenu: ', restaurant.mainMenu);
console.log('restaurant.starterMenu: ', restaurant.starterMenu);
const menu = [...restaurant.starterMenu, ...restaurant.mainMenu];
console.log(menu);
通过展开语法...
将字符串拆成单个字符
利用展开语法分解字符串中的字符,会返回一个由字符元素组成的数组并赋值给letters
变量。
ini
// 利用展开语法分解字符串中的字符
const str = 'yukon';
const letters = [...str, '', 'S.'];
console.log(letters);
console.log(...str);
⚠️注意:展开语法仅限于函数参数接收多个输入,或构建一个新数组。不要在模版字符串或其他函数中(如typeof()
)使用它,否则程序会返回一个错误,并中断程序。例如下面这个例子:
ini
const str = 'yukon';
const letters = [...str, '', 'S.'];
console.log(letters);
console.log(...str);
// 使用展开语法仅限于函数参数接收多个输入,或构建一个新数组时会用到
console.log(`${...str} Geegin`); // Error
另外,在JavaScript中可以对具有迭代类型的对象和函数使用展开语法。例如数组(Array)
、字符串(String)
、map
、集合set()
可以使用展开语法...
,注意不能对非迭代对象和函数使用展开语法...
,否则可能会产生程序错误🙅。
使用展开语法...
完成一个真实的项目
让我们修改对象,在原本对象的基础上增加一个点餐总结方法。在用户输入完要点的餐品后,把输入的输出到控制台上。
首先在restaurant
对象内创建orderPasta
方法。并将ing
变量作为此方法的输入参数。
arduino
const restaurant = {
name: '意大利🇮🇹经典',
location: 'Via Angelo Tavanti 23, 佛罗伦萨, 意大利',
categories: ['意大利', '比萨店', '素食', '有机'],
starterMenu: ['佛卡夏', '意式烤面包', '大蒜面包', '卡普雷塞沙'],
mainMenu: ['披萨', '意大利面', '烩饭'],
openingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open: 11,
close: 23,
},
sat: {
open: 0, // Open 24 hours
close: 24,
},
},
orderPasta: function (ing1, ing2, ing3) {
console.log(`这是你最喜欢的${ing1},${ing2},${ing3}烩饭`);
}
};
为了更加贴近用户的输入数据的方式,这里使用浏览器BOM的prompt
框来接收用户的输入。在过去的老版本中,用户输入完菜品后,需要依次调用ingredients
数组对应的索引。但如果你使用了ES6全新的方法,你可以直接使用展开语法即可调用ingredients
数组内的全部内容。
rust
// Real-world Example
const ingredients = [prompt('Let's make pasta! Ingredient 1 让我们做意大利面吧🍝 佐料一🍜'),
prompt('Ingredient 2 佐料二🧂'), prompt('Ingredient 3 佐料三🍅'),]
console.log(ingredients);
// INPUT: mashroom, aspargus, cheese or 黄瓜 番茄 奶酪
// Old way
restaurant.orderPasta(ingredients[0], ingredients[1], ingredients[2]);
// New way in ES6
restaurant.orderPasta(...ingredients);
大多数JavaScript中的元素都是可迭代的,但是对象除外。
另外展开语法语法...
同样可以对对象做操作
arduino
const restaurant = {
name: '意大利🇮🇹经典',
location: 'Via Angelo Tavanti 23, 佛罗伦萨, 意大利',
categories: ['意大利', '比萨店', '素食', '有机'],
starterMenu: ['佛卡夏', '意式烤面包', '大蒜面包', '卡普雷塞沙'],
mainMenu: ['披萨', '意大利面', '烩饭'],
openingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open: 11,
close: 23,
},
sat: {
open: 0, // Open 24 hours
close: 24,
},
},
orderPasta: function (ing1, ing2, ing3) {
console.log(`这是你最喜欢的${ing1},${ing2},${ing3}烩饭`);
}
};
ini
const newRestaurant = { foundedIn: 1998, ...restaurant, founder: '古商祺' }
console.log(newRestaurant);
通过展开语法,不仅可以将对象restaurant
中的属性和内容复制到newRestaurant
对象中,还可以同时加入多个不同的属性到newRestaurant
对象中。这种方式相当于对restaurant
对象进行了继承操作;在保留restaurant
属性值不变的情况下添加了不同的属性,从而形成了newRestaurant
对象。
另外扩展语法还经常被用于对象的复制。并且通过扩展语法复制出的对象实际上是对目标对象的深拷贝,并非简单的为对象(使用Object.assign()
方法)创建一个副本。例如下面这个例子🌰,利用展开语法将对象restaurant
中的属性和值全部复制到了restaurantCopy
对象中。接着单独对刚刚复制的对象restaurantCopy
下的name
属性命名为Ristorante Roma
。你会发现restaurantCopy
下的name
与restaurant
下的name
并不是一个。这证明通过展开语法复制出的对象是一种深拷贝。
ini
const restaurantCopy = { ...restaurant };
restaurantCopy.name = 'Ristorante Roma';
console.log('restaurantCopy: ', restaurantCopy);
console.log('restaurant: ', restaurant);
console.log('restaurantCopy.name: ', restaurantCopy.name);
console.log('restaurant.name: ', restaurant.name);
所以,对象深拷贝不仅可以使用JSON.parse(JSON.stringify())
方法,利用展开语法也是一个很不错的选择。
欢迎大家评论指教,一起学习,一起进步!