ES6学习二(函数rest参数和扩展运算符)

函数rest参数和扩展运算符

上一篇学习了ES6的变量以及变量的解构赋值,这次学习一些ES6的扩展方法。
函数rest参数和扩展运算符看起来比较相似,容易弄混,所以先把他们放在一起来学习。

1. 形式

首先来看,rest参数和数组或对象扩展运算符(spread)形式都是...变量名


2. rest参数

rest参数属于函数的扩展,是在函数声明时,用于获取不确定的函数参数(其实也可以在变量的解构赋值中声明变量使用)。

2.1 代替arguments对象

如果函数声明时只有一个rest参数,那个这个参数就可以代替arguments对象了。

// arguments变量的写法
function sortNumbers() {
    
    
  return Array.from(arguments).sort();
}
const res1 = sortNumbers(2,4,3,12,1)
console.log(res1); // [ 1, 12, 2, 3, 4 ]

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
const res1 = sortNumbers(2,4,3,12,1)
console.log(res1); // [ 1, 12, 2, 3, 4 ]

rest参数和arguments对象的区别:

  1. arguments对象是一个类数组对象,不能直接使用数组的方法,rest 参数搭配的变量就是一个真正的数组,即可以直接使用数组的方法。
  2. 函数的length属性是包括arguments对象的,但是不包括rest参数
function aoo(a) {
    
     }
function boo(arguments) {
    
     }
function coo(...arg) {
    
     }
function doo(frist, ...arg) {
    
     }

console.log(aoo.length); // 1
console.log(boo.length); // 1
console.log(coo.length); // 0
console.log(doo.length); // 1

2.2 剩余参数

如果函数声明时可以确定部分参数,但是剩下的不能确定,那么剩余的不确定参数都会被放到rest参数这个数组中。

function foo(frist, ...arg) {
    
    
  arg.push(frist)
  return arg
}

const foo1 = foo(1, 2, 3, 4)
const foo2 = foo('a', 'b', 1, 2, 3, 4)

console.log(foo1); // [ 2, 3, 4, 1 ]
console.log(foo2); // [ 'b', 1, 2, 3, 4, 'a' ]

2.3 变量的解构赋值中声明变量

在变量的解构赋值中,如果我们不确定能解构出哪些变量,也可以使用rest参数。
这时的rest就不一定是一个数组了,会根据解构的类型来定。
(文档中这段是算在扩展运算符中的)

const arr = [0, 1, 2, 3]
const [a1, ...restArr] = arr
console.log(restArr); // [ 1, 2, 3 ]

const obj= {
    
     b1: 1, b2: 2, b3: 3 }
const {
    
     b1, ...restObj } = obj
console.log(restObj); // { b2: 2, b3: 3 }

// 函数参数的解构赋值和rest参数
function foo({
     
      c, ...rest }) {
    
    
  return rest
}

const res = foo({
    
     a:1, b:2, c:5, d:4})
console.log(res); // { a: 1, b: 2, d: 4 }

2.4 只能做末尾参数

rest参数代表剩余参数,所以只能放在末尾,否则在使用的时候就会报错。

function foo( ...arg, last) {
    
    
  arg.push(last)
  return arg
}
foo(1, 2, 3, 4) // SyntaxError: Rest parameter must be last formal parameter

const arr = [0, 1, 2, 3]
const [...pre, last] = arr // SyntaxError: Rest element must be last element


3. 扩展运算符

扩展运算符属于数组对象的扩展。它好比 rest 参数的逆运算,将一个数组或对象转为用逗号分隔的参数序列。主要在函数调用或变量使用时用到。
注意,由上可以看出,rest代表的是一个集合,扩展运算符代表的是一个序列,这也是我将解构赋值等号左边的内容放到rest的原因。

3.1 序列化函数入参

扩展运算符可以将数组拆分成以逗号分隔的序列

const arr = [1, 2, 5]

function foo(a,b,c) {
    
    
  console.log(a);
  console.log(b);
  console.log(c);
}

foo(arr)
// [ 1, 2, 5 ]
// undefined
// undefined

foo(...arr)
// 1
// 2
// 5

替代函数的 apply 方法

例如Math.max()的参数是逗号分隔一个一个的,这时如果要比较一个数组的大小,需要使用apply方法辅助,但是扩展运算符就可以将这个数组序列化,相当于直接使用Math.max()

// ES5 的写法
Math.max.apply(null, [14, 3, 77])

// ES6 的写法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);

3.2 复制数组或对象(浅拷贝)

数组或对象是引用类型的数据,直接复制只是复制了指向底层数据结构的指针,对复制的变量进行修改还是会影响到原来的变量。
扩展运算符提供了复制数组或对象的简便写法,实现浅拷贝

const arr = [1, 2, 3]
const arr1 = arr
const arr2 = [...arr]

arr1.push(4)
arr2.push(5)

console.log(arr); // [ 1, 2, 3, 4 ]
console.log(arr1); // [ 1, 2, 3, 4 ]
console.log(arr2); // [ 1, 2, 3, 5 ]

// 多层级的引用类型数据,修改复制变量仍然会影响原变量
const arr3 = [[1, 2]]
const arr4 = [...arr3]
arr4.push(6)
arr4[0].push(7)
console.log(arr3); // [ [ 1, 2, 7 ] ]
console.log(arr4); // [ [ 1, 2, 7 ], 6 ]

3.3 合并数组或对象

扩展运算符提供了数组或对象合并的新写法。

// 合并数组
const arr1 = [1, 3, 4]
const arr2 = [2, 5, 6]

// ES5 的写法
const mergeArr1 = arr1.concat(arr2)

// ES5 的写法
const mergeArr2 = [...arr1, ...arr2]

console.log(mergeArr1); // [ 1, 3, 4, 2, 5, 6 ]
console.log(mergeArr2); // [ 1, 3, 4, 2, 5, 6 ]

// 合并对象
const obj1 = {
    
     a: 1, b: 2 }
const obj2 = {
    
     c: 3, d: 4 }

// ES5 的写法
let mergeObj1 = {
    
    }
for (const key in obj1) {
    
    
  mergeObj1[key] = obj1[key]
}
for (const key in obj2) {
    
    
  mergeObj1[key] = obj2[key]
}

// ES5 的写法
const mergeObj2 = {
    
     ...obj1, ...obj2 }

console.log(mergeObj1); // { a: 1, b: 2, c: 3, d: 4 }
console.log(mergeObj2); // { a: 1, b: 2, c: 3, d: 4 }

3.4 将字符串转为数组

扩展运算符还可以将字符串转为真正的数组。

[...'hello']
// [ "h", "e", "l", "l", "o" ]

扩展运算符能够正确识别四个字节的 Unicode 字符。

'x\uD83D\uDE80y'.length // 4
[...'x\uD83D\uDE80y'].length // 3

上面代码的第一种写法,JavaScript 会将四个字节的 Unicode 字符,识别为 2 个字符,采用扩展运算符就没有这个问题。
注意:凡是涉及到操作四个字节的 Unicode 字符的函数,都有这个问题。因此,最好都用扩展运算符改写。

3.5 实现了 Iterator 接口的对象

(暂时还不会Iterator )
TODO…

3.6 Map 和 Set 结构,Generator 函数

(暂时还不会Generator )
TODO…

猜你喜欢

转载自blog.csdn.net/BAtodl/article/details/120446173
今日推荐