ES6系列之函数

1.函数参数的默认值
ES6容许为函数的参数设置默认值,即直接写在参数定义的后面。编程

function log(x, y = 'World') {
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

使用参数默认值时,函数不能有同名参数。
另外,一个容易忽略的地方是,参数默认值不是传值的,而是每次都从新计算默认值表达式的值。也就是说,参数默认值是惰性求值的数组

与解构赋值默认值结合使用
参数默认值能够与解构赋值的默认值,结合起来使用。函数式编程

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

函数的length属性(函数预期传入参数的个数)
指定了默认值之后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。函数

做用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会造成一个单独的做用域(context)。等到初始化结束,这个做用域就会消失。this

2.rest参数
ES6引入rest参数(形式为…变量名),用于获取函数的多余参数,这样就不须要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。prototype

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10


// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();

注意,rest参数以后不能再有其余参数(即只能是最后一个参数),不然会报错。
函数的length属性,不包括rest参数rest

4.name属性
函数的name属性,返回该函数的函数名。
function构造函数返回的函数实例,name属性的值为anonymous。
bind返回的函数,name属性值会加上bound前缀。code

5.箭头函数
若是箭头函数不须要参数或须要多个参数,就使用一个圆括号表明参数部分。
若是箭头函数的代码块部分多于一条语句,就要使用大括号
将它们括起来,而且使用return语句返回。
var sum = (num1, num2) => { return num1 + num2; }对象

因为大括号被解释为代码块,因此若是箭头函数直接返回一个对象,必须在对象外面加上括号,不然会报错。递归

// 报错
let getTempItem = id => { id: id, name: "Temp" };

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });

箭头函数与rest参数结合的例子

const numbers = (...nums) => nums;

numbers(1, 2, 3, 4, 5)
// [1,2,3,4,5]

const headAndTail = (head, ...tail) => [head, tail];

headAndTail(1, 2, 3, 4, 5)
// [1,[2,3,4,5]]

箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不能够当作构造函数,也就是说,不可使用new命令,不然会抛出一个错误。
(3)不可使用arguments对象,该对象在函数体内不存在。若是要用,能够用rest参数代替。
(4)不可使用yield命令,所以箭头函数不能用做Generator函数。

this指向的固定化,并非由于箭头函数内部有绑定this的机制,实际缘由是箭头函数根本没有本身的this,致使内部的this就是外层代码块的this。正是由于它没有this,因此也就不能用做构造函数。

6.尾调用
尾调用(tail call)是函数式编程的一个重要概念,自己很是简单,一句话就能说清楚,就是指某个函数的最后一步是调用另外一个函数。
尾调用之因此与其余调用不一样,就在于它的特殊的调用位置。
咱们知道,函数调用会在内存造成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。若是在函数A的内部调用函数B,那么在A的调用帧上芳,就造成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。若是函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。全部的调用帧,就造成一个“调用栈”(call stack)。

尾调用因为是函数的最后一步操做,因此不须要保留外层函数的调用帧,由于调用位置、内部局部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就能够了。

函数调用自身,称为递归。若是尾调用自身,就称为尾递归。递归很是耗费内存,由于须要同时保存成千上百个调用帧,很容易发生“栈溢出”(stack overflow)。但对于尾递归来讲,因为只存在一个调用帧,多以永远不会发生“栈溢出”错误。

相关文章
相关标签/搜索