ES6学习二(函数rest参数和扩展运算符)
ES6学习二
- 函数rest parameter与扩展运算符
- 第一部分:形式
-
第二部分:rest parameter
- 第二部分包含以下几点:
- 第一部分: 替代arguments对象:
- 描述了如何通过这种方式替代arguments对象。
- 第二部分: 剩余parameter:
- 解释了剩余parameter的概念。
- 第三部分: 在variable destructuring assignment中声明variable name:
- 讨论了如何在variable destructuring assignment过程中声明variable name。
- 最后一部分: 只限于作为最后一个接受的parameter:
- 解释了这种parameter只能作为最后一个接受的parameter的特点。
- 第一部分: 替代arguments对象:
- 第二部分包含以下几点:
-
3. 扩展运算符
-
- 3.1 序列化函数入参
-
- 替代函数的 apply 方法
-
3.2 创建浅拷贝的数组或对象
3.3 拼接数组或对象
3.4 将字符串转换成数组
3.5 支持Iterator接口的对象实现
3.6 Map、Set数据结构与生成器函数
函数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对象的区别:
- arguments 对象是一种类数组类型,在此情况下无法直接调用内置的数组方法。然而,在这种情况下通过 rest 参数传递的参数构成一个真实的数组(即可以直接调用内置的数组方法)。
- 函数长度属性包含了 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 变量的解构赋值中声明变量
在变量的解构赋值操作中,默认情况下如果无法预知可解构的变量列表,则应调用RestParameter。这种情况下对应的参数不再是数组类型而是采用了一种更灵活的数据结构。需要注意的是这段内容主要涉及扩展运算符这一知识点。
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位置。
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字符解析为两个字符。采用扩展运算符来处理就不会出现这个问题。任何需要处理四个字节的Unicode字符的操作函数都会面临这一问题。因此建议在代码中尽可能使用扩展运算符来解决这个问题。
3.5 实现了 Iterator 接口的对象
(暂时还不会Iterator )
TODO…
3.6 Map 和 Set 结构,Generator 函数
(暂时还不会Generator )
TODO…
