欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6快速入门第八章------ 函数的扩展 (可私信解惑)

程序员文章站 2022-07-16 22:04:50
...
  • 箭头函数

ES6允许使用“箭头”(=>)定义函数。箭头函数使得表达更加简洁。

var    f = (参数)=>{ 代码块}
var    ff = (x,y)=>{ return x+y }

// 相当于
var f = function(参数){ 代码块 }
var ff = function(x,y){ return x+y }

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。

 

箭头函数可以与变量解构结合使用。

const full = ({ first, last }) => first + ' ' + last;
// 等同于

var person={ first, last };
function full(person) {

  return person.first + ' ' + person.last;
}

箭头函数可以嵌套使用。一个箭头函数大括号中可以嵌套另一个箭头函数。

  • 箭头函数this对象指向(详细介绍请阅读我的另外一篇博文)

普通函数this 的指向

  • js中的this是执行上下文,在普通函数中,this指向它的直接调用者;
  • 在默认情况下(非严格模式),在全局环境下,js中的this指向window;

箭头函数的this指向

箭头函数体内的this对象就是定义时所在的对象,而不是使用时所在的对象。

简单而言,箭头函数使用时,不绑定this对象,箭头函数没有自己的this,它的this是继承而来的,默认指向在定义箭头函数时所处的对象。

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}
var f = foo.call({id: 1});        // 设置foo的id为1
var t1 = f.call({id: 2})()();     // id: 1
var t2 = f().call({id: 3})();     // id: 1
var t3 = f()().call({id: 4});     // id: 1

上面代码之中,只有一个this,就是函数foo的this。所以t1、t2、t3都输出同样的结果。

因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。所以箭头函数的this指向是创建它所在的对象,不会改变。

 

箭头函数有几个使用注意点:

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

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

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

(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

  • 函数的默认值

在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。

function log(x, y) {
    y = y || 'aaa';        // 设置y的默认值为aaa
    console.log(x, y);
}

ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = 'aaa') {
    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

上面代码使用了对象的解构赋值默认值,而没有使用函数参数的默认值。只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值而生成。如果函数foo调用时参数不是对象,变量x和y就不会生成,从而报错。如果参数对象没有y属性,y的默认值5才会生效。

 

  • 函数的length属性

指定了默认值以后,函数的length属性,返回的是没有默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

下面代码中,length属性的返回值,等于函数的参数个数减去指定了默认值的参数个数。

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

 

如果设置了默认值的参数不是尾参数(排在最右边),那么length属性也不再计入后面的参数了(就是说,以第一个默认参数位置开始计数,只计算第一个默认参数前边的个数,不计算后边的)。

如下面代码第一行,默认参数a在最左边位置,右边参数b和c虽然不是默认参数,但是在默认参数后边(右边),所以不计参数b和c了。

第二行代码中,排在默认参数b前面(左边)的参数a计入length,而排在默认参数后面(右边)的参数c则不计入。

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

 

  • 函数默认值的作用域

作用域问题

var x=1;    // 全局变量x
function f(x, y = x) { console.log(y);  }

上面代码中,参数y的默认值等于x。调用时,由于函数作用域内部的变量x已经生成,所以y等于参数x,而不是全局变量x。

let x = 1;        // 全局变量 x
function f(y = x) {
  let x = 2;        // 局部变量 x 
  console.log(y);
}
f() // 1

上面代码中,函数调用时,y的默认值变量x尚未在函数内部生成,所以x指向全局变量。

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

function add(...values) {
  let sum = 0;
  for (var num of values) {
    sum += num;
  }
  return sum;
}
add(4, 5, 6,7)    // 22

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

  • 扩展运算符

扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log( ...[1, 2, 3] )    // 1   2   3
console.log(  ...[1, 2, ...[1,2,5],3] )    // 1  2  1  2  5  3
console.log(  ...[1, 2, [1,2,5],3] )    // 1  2  [ 1, 2, 5 ]  3

该运算符主要用在函数调用

function add(x, y) {
    return x + y;
}
var numbers = [4, 38];
add(...numbers)     // 42
  • 尾调用和尾递归

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

function f(x){
    return g(x);
}

上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。

 

函数调用自身,称为递归。

如果尾调用自身称为尾递归

function foo(n) {
  if (n === 1) return 1;
  return n * foo(n - 1);
}
foo(5)     // 120

第九章:ES6看完必会第九章------ 对象的扩展 (可私信解惑,不会来捶我)