函数的拓展
参数的默认值
在ES6
之前,函数传入的参数没有默认值这一说法,所以我们经常要进行一些参数校验
function log(x, y) { if (typeof y === 'undefined') { y = 'world' } console.log(x, y) } log('hello')// hello world log('hello', '') // hello log('hello', 'abc')//hello abc
ES6
允许为函数的参数设置默认值,即直接写在参数定义的后面。
function log(x, y = 'world') { console.log(x, y) } log('hello') //hello world log('hello', '')//hello log('hello', 'abc')//hello abc
与解构赋值默认值结合使用
参数默认值可以与解构赋值的默认值,结合起来使用。
function foo({ x, y = 5}) { console.log(x, y) } foo({x:1,y:2}) //1,2 foo({})// undefined 5 foo()// TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
函数的length属性
指定了默认值以后,函数的length
属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length
属性将失真。
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
rest参数
ES6 引入 rest
参数(形式为...变量名
),用于获取函数的多余参数,这样就不需要使用arguments
对象了。rest
参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...val) { let sum = 0 sum = val.reduce(((pre, cru) => { return pre + cru })) console.log(sum)}add(1, 2, 3) } add(1,2,3)
name属性
函数的name
属性,返回该函数的函数名
function add(...val) { ···} add.name //add
箭头函数
let f = v => v //相当于 let f = function (v) { return v }
如果需要多个参数,则可以把参数放入圆括号中
let add = (num1, num2) => num1 + num2
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用 return
语句返回。
var sum = (num1, num2) => { return num1 + num2; }
注意点
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用rest
参数代替。 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数。
尾递归
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow
)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1); } factorial(5) // 120
上面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n)
。
如果改写成尾递归,只保留一个调用记录,复杂度 O(1)
。
function factorial(n, total) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5, 1) // 120
数组的拓展
拓展运算符
含义
扩展运算符(spread)是三个点(...
)。它好比 rest
参数的逆运算,将一个数组转为用逗号分隔的参数序列
复制代码
console.log(...[1,2,3]) //1 2 3 console.log(1,...[2,4,5],6) //1 2 4 5 6
替代apply
方法
下面是一个利用Math.max
求最大值的例子
//ES5 Math.max.apply(null, [1, 2, 3]),//3 //ES6 Math.max(...[1, 2, 3])//3
拓展运算符的运用
- 复制数组
let arr1 = [1,2] let arr2 = arr1 arr2[1] = 'a' console.log(arr1,arr2) //[ 1, 'a' ] [ 1, 'a' ]
数组是一个复杂类型,直接用等号赋值的话实际上只是复制了它的指针,即arr1
、arr2
指向的是同一块内存。
//ES5 let arr1 = [1,2] let arr2 = arr1.concat() //拓展运算符 let arr1 = [1,2] let arr2 = [...arr1]
- 合并数组
扩展运算符提供了数组合并的新写法。
const arr1 = ['a', 'b']; const arr2 = ['c']; const arr3 = ['d', 'e']; // ES5 的合并数组 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6 的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
不过,这两种方法都是浅拷贝,使用的时候需要注意。
const a1 = [{ foo: 1 }]; const a2 = [{ bar: 2 }]; const a3 = a1.concat(a2); const a4 = [...a1, ...a2]; a3[0] === a1[0] // true a4[0] === a1[0] // true
Array.from
Array.from
方法用于将两类对象转为真正的数组:类似数组的对象(array-like object
)和可遍历(iterable
)的对象(包括 ES6
新增的数据结构 Set
和 Map
)。
下面是一个类似数组的对象,Array.from
将它转为真正的数组。
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()
Array.of
方法用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1
entries(),keys() 和 values()
ES6
提供三个新的方法——entries()
,keys()
和values()
——用于遍历数组。它们都返回一个遍历器对象,可以用for...of
循环进行遍历,唯一的区别是keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历。
for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b"