函数的扩展
函数的扩展
  函数参数的默认值
    ES6 允许为函数的参数设置默认值
    直接写在参数定义的后面
      function log(x, y = 'World') {
console.log(x, y);
}
    默认参数与解构赋值默认值结合使用
      参数默认值可以与解构赋值的默认值，结合起来使用
        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属性的含义是，该函数预期传入的参数个数
      所以指定了默认值以后，函数的length属性，将返回没有指定默认值的参数个数。
        (function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
      如果使用rest 参数，也不会计入length属性
        (function(...args) {}).length // 0
      如果设置了默认值的参数不是尾参数，那么length属性也不再计入后面的参数了
        (function (a = 0, b, c) {}).length // 0
        (function (a, b = 1, c) {}).length // 1
    作用域
      一旦设置了参数的默认值，函数进行声明初始化时，参数会形成一个单独的作用域
      等到初始化结束，这个作用域就会消失。
  rest 参数
    rest 参数（形式为...变量名）
    用于获取函数的多余参数
    用于代替arguments对象
    注意，rest 参数之后不能再有其他参数（即只能是最后一个参数），否则会报错
      // 报错
function f(a, ...b, c) {
// ...
}
    函数的length属性，不包括 rest 参数
  严格模式
    从 ES5 开始，函数内部可使用'use strict'设定为严格模式
    ES2016 做了一点修改，规定只要函数参数使用了默认值、解构赋值、或者扩展运算符，那么函数内部就不能显式设定为严格模式，否则会报错
      // 报错
function doSomething(a, b = a) {
'use strict';
// code
}
    两种方法可以规避这种限制
      第一种是设定全局性的严格模式
      第二种是把函数包在一个无参数的立即执行函数里面
  name 属性
    函数的name属性，返回该函数的函数名
    这个属性早就被浏览器广泛支持，但是直到 ES6，才将其写入了标准。
    需要注意：如果将一个匿名函数赋值给一个变量，ES5 的name属性，会返回空字符串，而 ES6 的name属性会返回实际的函数名
      var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
    Function构造函数返回的函数实例，name属性的值为anonymous
      (new Function).name // "anonymous"
    bind返回的函数，name属性值会加上bound前缀
      function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
  箭头函数
    ES6 允许使用“箭头”（=>）定义函数
    如果箭头函数不需要参数或需要多个参数，就使用一个圆括号代表参数部分
    如果箭头函数的代码块部分多于一条语句，就要使用大括号将它们括起来
    由于大括号被解释为代码块，所以如果箭头函数直接返回一个对象，必须在对象外面加上括号，否则会报错
      // 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
    一种特殊情况，虽然可以运行，但会得到错误的结果
      let foo = () => { a: 1 };
foo() // undefined
    如果箭头函数只有一行语句，且不需要返回值，就不用写大括号
    箭头函数可以与变量解构结合使用
      const full = ({ first, last }) => first + ' ' + last;
    使用注意点
      箭头函数没有自己的this对象
      不可以当作构造函数
      不可以使用arguments对象
      不可以使用yield命令
    不适用场合
      定义对象的方法，且该方法内部包括this
      需要动态this的时候，也不应使用箭头函数
    嵌套的箭头函数
    尾调用优化
      尾调用就是指某个函数的最后一步是调用另一个函数
        function f(x){
return g(x);
}
      尾调用不一定出现在函数尾部，只要是最后一步操作即可
        function f(x) {
if (x > 0) {
return m(x)
}
return n(x);
}
      尾调用优化，即只保留内层函数的调用帧
      ES6 的尾调用优化只在严格模式下开启
    尾递归
      函数调用自身，称为递归。如果尾调用自身，就称为尾递归
    柯里化（currying）
      将多参数的函数转换成单参数的形式
    函数参数的尾逗号
      ES2017 允许函数的最后一个参数有尾逗号
  Function.prototype.toString()
    返回函数代码本身，包括注释和空格
  catch 命令的参数可省略
    try {
// ...
} catch {
// ...
}