js知识点-拓展运算符和剩余运算符

概述

在现代JavaScript开发中,ES6引入的拓展运算符(Spread Operator)和剩余运算符(Rest Operator)让代码更加简洁和灵活。

无论是数组、对象的拆分与合并,还是函数参数的处理,这两个运算符都是非常实用的工具。

拓展运算符

1.什么是拓展运算符?

拓展运算符(Spread Operator)由三个连续的点 ... 表示,用于将一个可迭代对象(例如数组、字符串等)展开成多个元素。

拓展运算符可以应用在数组或对象上,实现数据的拆分、复制、合并等操作。

2.拓展运算符的作用

拓展运算符号主要应用于以下三个场景:

  • 数组的复制和合并
  • 对象的复制和合并
  • 函数调用时传递数组作为多个参数

3.拓展运算符使用示例

3.1数组的拓展

使用演示

let arr = ["hello","happy"]

let arr1 = ["ok","no",...arr]

代码讲解

...可迭代对象,例如数组,相当于遍历该迭代对象,得到每一个元素。

let arr1 = ["ok","no",...arr]

等价于

let arr1 = ["ok","no"]
for(let i=0;i<arr.length;i++){
    arr1.push(arr[i])
}

更形象的理解是,直接把数组元素铺开放入,所以叫做拓展运算符。

3.2对象的拓展

使用演示

let obj = {
    name:"zhansan",
    age:19
}

let student = {
    ...obj,
    gender:"man",
}

代码讲解

...对象,相当于遍历对象,将该对象展开,得到每一组属性和值。

let student = {
    ...obj,
    gender:"man",
}

等价于

let student = {gender:"man"}
for(let key in obj){
    student[key] = obj[key]
}

本质上就是拓展原对象,然后给新对象增加属性。所以遇到已存在的属性,新出现的会覆盖之前的,例如

let tmp1 = {
    age:19
}

let tmp2 = {
    age:25
}

let res = {
    ...tmp1,
    ...tmp2
}

最终结果为

//因为按照展开顺序,
// ...tmp1时,res[age] = 19
// ...tmp2时,重新赋值,res[age]=25
res = {
    age:25
}
3.3 可遍历对象展开

凡是可以遍历的对象都可以使用拓展运算符号。

js中都是对象,字符串也属于可遍历的对象。

let str = "hello"

let arr = [...str]

console.log(arr);//["h","e","l","l","o"]
3.4 函数传参

本质上还是将数组和对象展开,

let arr = [1,2,3]

//只接收一个参数
function single(arr){
    return arr
}

//接收多个参数
function more(a,b,c){
    return a+b+c
}

传参示例

//直接传递整个数组作为参数
single(arr)

//将数组元素展开后再传入
more(...arr)
//相当于
more(1,2,3)
注意事项

传入引用类型

其实传入整个数组和拓展数组再传入是有不同的应用场景的。

let arr = [1,2,3]

function getSum(nums){
    nums[1] = 5
    return nums.reduce((a,b)=>a+b,0)
}

//由于数组是引用类型,所以我们传入后,函数内对数组的修改会影响到外部原始数组
getSum(arr)

console.log(arr);//[5,2,3]

而拓展运算符传入时,我们内部再改变参数,如果该参数不是引用类型则对外部没有影响,例如

let arr = [1,2,3]

//对于参数数量,未来可以使用剩余运算符或者内置arguments对象
function getSum(a,b,c){
    a = 5
    return a+b+c
}

getSum(...arr)

console.log(arr)//[1,2,3]

位置参数

当我们传递拓展元素时,会按照位置进行传递。

let arr = [1,2,3]

function getVal(a){
    console.log(a)
}

getVal(...arr)
//最终调用相当于 getVal(1)
//因为函数只接收一个参数,多于的参数会被忽略

4.拓展运算符是浅拷贝

拓展运算符就等价于遍历可迭代的对象,将原对象的每一项提取,所以他是一个浅层拷贝。

let arr = [1,2,{age:19}]

在数组arr中有一个引用类型的元素{age:19},当我们进行...arr时,例如

let arr1 = [...arr]

//本质上对于{age:19}执行的是如下操作
let tmp = {age:19}
arrNew.push(tmp)

而引用类型赋值时传递的是引用,所以arrarrNew中的{age:19},指向同一个引用。

验证

let arr = [1,2,{age:19}]
let arrNew = [...arr]

//变动前
console.log(arr)//[1,2,{age:19}]
console.log(arrNew)//[1,2,{age:19}]

//获取对象并重新赋值
arrNew[2]['age'] = 25

//验证
console.log(arr)//[1,2,{age:25}]
console.log(arrNew)//[1,2,{age:25}]

剩余运算符

在mdn的百科中被称为剩余参数剩余属性

1.背景

在函数传参时,常常会出现参数不确定的情况,传统的做法是使用函数内置的arguments对象,例如:

function getSum(){
    //arguments是函数内置对象,是一个类数组,用于接收所有参数
    console.log(arguments)
}

arguments是函数内置对象,是一个类数组,用于接收所有参数。

我们可以通过遍历该对象来对所有参数进行处理,例如

function getSum(){
    let sum = 0
    for(let i =0;i<arguments.length;i++){
        sum += arguments[i]
    }
    return sum
}

getSum(1) //1
getSum(1,2,3,4)//10

特点

函数的参数(无论有无形参)最终都会被arguments对象收集。

局限性

1.arguments对象是古老产物,是个类数组,很多新的针对迭代对象的方法是用不了的(因为迭代对象是后来加入的),例如mapforEach等方法。

2.箭头函数没有内置arguments对象(因为现代js更推荐使用剩余运算符)。

2.剩余运算符是什么?

剩余运算符(Rest Operator)也是由 ... 表示,但在函数参数或解构赋值中使用,通常用来接收不确定数量的参数或对象属性,并将其“收集”到一个数组或对象中。

其实arguments对象,可以借助拓展运算符,例如[...arguments]变成真数组.

这可能就是剩余运算符的最初含义。

3.剩余运算符的作用

剩余运算符的主要运用场景:

  • 函数参数的收集
  • 对象或数组解构赋值时的剩余元素收集

4.剩余运算符使用举例

4.1函数参数的收集

当我们不确定函数参数数量时,可以用...变量来收集多有的参数,该变量会成为一个真数组,收集所有未接收参数。

function getSum(a,...nums){
    console.log("第一个参数为",a)
    console.log("其他参数为",nums)
}

//函数调用
getSum(10,11,1,2,5)

运行结果

第一个参数为10
其他参数为[11,1,2,5]
4.2对象解构时的剩余属性

解构对象时,如果我们想要用一个对象接收所有剩余的属性,可以使用{...变量},例如

let objOrigin = {
    value:"hello",
    label:"你好",
    order:5
}

//解构
const {val,...others} = objOrigin

console.log(val);//"hello"
console.log(others);//{ label:"你好",order:5 }
4.3数组解构时的剩余属性

解构数组时,可以用一个数组收集所有剩余元素。

let arrOrigin = ["javascript","java","C++","Rust","Golang"]

const [first,...coding] = arrOrigin 

console.log(first);//"javascript"
console.log(coding);//["java","C++","Rust","Golang"]

5.注意事项

由于剩余运算符是接收所有剩下的元素,所以放在接收的最后,其后不应该再出现其他接收者,例如:

错误示范

//此处的形参happy是不可能接收到内容的
function getVal(...args,happy){
    ...
}

拓展运算符与剩余运算符两者异同

相同点

  • 符号一致,都是...
  • 都与可遍历的对象有关(这里尽量不用可迭代对象一词,因为js中可迭代对象是专有名词)。

可遍历的对象不一定可以迭代,例如伪数组、字符串。

但是可迭代对象一定可以遍历,例如数组。

不同点

二者可以看作是逆运算,拓展运算符是将可遍历的对象展开成一个个元素。

剩余运算符号是将一个个元素接收,拼接成可遍历的对象。

你可能感兴趣的:(javascript,开发语言,ecmascript)