长沙尚学堂|十年树人|成就高薪
致力推动IT教育,我们正在行动    全国咨询热线:0731-83072091

2018WEB前端ES6 中的函数扩展

时间:2018-01-08 09:33:15   来源:网络转载   阅读:

    函数参数的用法,参数默认值的设置,与ES5 对比,ES5中设置参数默认值的写法,2018WEB前端ES6 中的函数扩展,分享给大家,希望能够对大家有所帮助吧。

  function animal(name, type) {

  var name = name || 'yuan';

  var type = type || 'monkey';

  console.log(name, type);

  }

  这个写法有个缺陷:参数传递进来的布尔值必须为true,如果传入的值为空字符串或者undefined 等这些转换为false的参数,则会影响结构。所以,ES6为了弥补这个缺陷,做了如下设置:

  function animal(name = 'yuan', type = 'monkey') {

  console.log(name, type);

  }

  2、传入参数类型对输出结果的影响

  function animal(name = 'yuan', type = 'monkey') {

  console.log(name, type);

  }

  animal(); // yuan monkey

  animal(name = 'dog'); // dog monkey

  animal(name = 'yuan', undefined); // yuan monkey

  animal(name = 'yuan', null); // yuan null

  animal(false, undefined); // false "monkey"

  animal(0, undefined); // 0 "monkey"

  上面代码4中调取函数的方式,只有不传和传入undefined 的会触发默认值,而传入其它值或者null,则不会触发默认值。

  3、注意参数放置位置

  // 错误写法

  function animal(name = 'yuan', type) {

  console.log(name, type);

  }

  // 正确写法

  function animal(name, type = 'monkey') {

  console.log(name, type);

  }

  如上,在设置了默认值的参数后,就不需要在设置其他参数了,通常情况下,若有参数为默认值时,一般是放在尾参数位置。

  4、参数默认值与解构赋值默认值的结合使用

  对比下面两种写法

  // 第一种写法,参数默认值为空对象,解构赋值有具体的默认值

  function method1({x = 0, y = 0} = {}) {

  return [x, y];

  }

  // 第二种写法,参数默认值是一个具体的属性对象,而对象解构赋值没有设置默认值

  function method2({x, y} = {x: 0, y: 0}) {

  return [x, y];

  }

  // 函数没有参数时

  method1(); // [0, 0]

  method2(); // [0, 0]

  // x 和 y 都有值

  method1({x: 2, y: 3}); // [2, 3]

  method2({x: 2, y: 3}); // [2, 3]

  // x 有值, y 没有值

  method1({x: 2}); // [2, 0]

  method2({x: 2}); // [2, undefined]

  // x 没有值, y 有值

  method1({y: 2}); // [0, 2]

  method2({y: 2}); // [undefined, 2

  // x 和 y 都没有值

  method1({}); // [0, 0]

  method2({}); // [undefined, undefined]

  5、使用参数默认值对函数length 属性的影响

  (function (a) {}).length // 1

  (function (a = 5) {}).length // 0

  (function (a, b, c = 5) {}).length // 2

  (function(a, ...b) {} ).length // 1

  由上面代码可以看出,函数的参数在指定默认值之后,函数的length 属性会失真,返回的length 值,是没有指定默认值的参数的个数,注意这里的length 也不包括rest参数(如第二点介绍)的个数。

  6、注意点

  因函数参数是默认声明的,如果如果用let 或 const 重新声明变量,会报错:

  function animal(name = "yuan") {

  let name = dog;

  console.log(name);

  }

  animal(); // 报错: Uncaught SyntaxError: Identifier 'name' has already been declared

  二、rest 参数

  案例 呈现

  // 求和,把结果赋值给 result

  function sum(result, ...values) {

  console.log(values); // [1, 2, 3, 4],这个变量返回的是一个数组

  values.forEach( function(value, index) {

  result += value;

  })

  console.log(result);

  }

  sum(11, 1, 2, 3, 4,); // 21

  如上,rest参数(3个点 + 变量名)表示的是:获取函数多余的参数,且这个变量是一个数组。还有一点要注意的是rest参数必须是尾参数,后面不能加其他的参数,否则会报错:

  // 错误写法

  function sum(res, ...values, another) {

  console.log(values);

  }

  sum(); // 报错:Uncaught SyntaxError: Rest parameter must be last formal parameter

  三、name属性

  ES6中增加了函数的name属性

  const animal = function() {};

  animal.name; // "animal"

  Function 构造函数会发的函数实例,name 属性的值为“anonymous”

  (new Function).name; // "anonymous"

  bind 返回的函数,name属性值会加上“bound”前缀

  function animal() {};

  animal.bind({}).name; // "bound animal"

  匿名函数的bind 返回的值“bound”

  (function () {}).bind({}).name; // "bound"

  四、箭头函数

  1、定义

  用箭头“=>”来定义函数。

  2、用法

  对比

  // ES5 写法

  var sum = function(a) {

  return a;

  }

  // ES6 写法

  var sum = a => a;

  如上代码,在ES6中,第一个a表示函数参数,箭头“=>”后面的 a 表示函数体。

  上述只是针对一个参数和函数体只有一条语句的写法,若函数参数的个数和函数体的语句超过1个要如何表示呢?如下:

  var sum = (a, b) => { return a + b};

  sum(1,4); // 5

  如上,若函数的参数个数超过一个时,需要用圆括号“()”来代表参数,函数体的语句条数超过一条时,需要用大括号将它们括起来。

  当函数体中返回的是对象时,我们需要将其用圆括号“()”括起来:

  var person = name => ({ name: 'yuan', type: 'monkey'});

  3、使用注意点

  (1)、函数体内的 this 指向,指向的是定义时所在的对象,而不是使用时所在的对象。

  在箭头函数中 this 指向是固定的:

  function foo() {

  setTimeout( () => {

  console.log('id:', this.id)

  }, 100);

  }

  var id = 21;

  foo.call({ id: 42}); // 42

  如上输出结果,此处的this 指向并不是全局对象 window,因为在箭头函数中,this 总是指向函数定义生效时所在的对象,所以输出的结果是 42。

  如果还不清楚箭头函数 this 指向的含义,我们可以这样通俗的理解:在JavaScript 中每一个 function 都有一个独立的运行上下文,而箭头函数不是一个普通的 function ,没有自己的运行上下文。所以在箭头函数中写的 this,具体指的是包含这个箭头函数最近的 function 的上下文中的 this,如果没有最近的 function,this 指向的是全局。

  (2)、不能当做构造函数用,即不能使用 new 命令,否则会报错

  (3),、不可以使用arguments 对象,该对象哎函数体内不存在。如果要用,使用 rest 参数代替

  (4)、不能使用 yield 命令,因为箭头函数不能用作Generator 函数

  六、函数的尾调用

  1、定义

  尾调用是函数式编程的一个重要概念,是指某个函数的最后一步调用另一个函数。

  function f(x) {

  return g(x);

  }

  函数f 的最后一步是调用函数g,这就是尾调用。

  2、尾递归

  函数调用自身叫做递归,如果尾调用自身就是尾递归。

  function factorial(n) {

  if(n === 1) return 1;

  return n * factorial(n - 1);

  }

  factorial(5); // 120

  在ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存。

  3、尾递归改写

  为了确保最后一步只调用自身,需要对尾递归函数进行改写,把所有用到的内部变量改写成函数的参数。

  使用柯里化函数编程思想,将多参数的函数转换成单参数的形式:

  function curring(fn, n) {

  return function (m) {

  return fn.call(this, m, n);

  }

  }

  function tailFactorial(n, total) {

  if(n === 1) return total;

  return tailFactorial(n - 1, n * total);

  }

  const factorial = curring(tailFactorial, 1);

  factorial(5); // 120

  采用ES6的函数默认值改写:

  function factorial(n, total = 1) {

  if(n === 1) return total;

  return factorial(n - 1, n * total);

  }

  factorial(5); // 120

  在尾调用优化时,循环是可以用递归代替的,而一旦使用递归,就最好使用尾递归。

  五、总结

  1、本章需要掌握ES6中函数的表示方式,以及 rest 参数的使用。

  2、本章重点:箭头函数的表示方法,以箭头函数使用的注意事项,特别是箭头函数中 this 的指向问题。

  2018WEB前端ES6 中的函数扩展,就跟大家讲解到这,欢迎大家点击弹窗私聊长沙尚学堂客服,免费领取教学视频!
 

学大数据

  推荐阅读:

  2017长沙哪家WEB前端培训机构比较好

  2017长沙最好的软件培训学校排行榜

  2017长沙学UI设计多少钱

标签:学WEB前端
分享:0
开班计划

试听申请表

全程面授,不高薪都难

报名成功后,尚学堂工作人员将在24小时内与您联系

热门文章
视频下载
猜你喜欢

有位老师想和您聊一聊