ES6箭头函数详解

499 阅读4分钟

-------大鹏一日同风起,扶摇直上九万里 《上李邕李白

什么是箭头函数?

箭头函数是ES6标准新增的一种函数 ,语法上相对于普通函数更简洁

一、基本语法

x => x * x

相当于

function (x) {
  return x * x;
}

如果需要传多个参数

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

如果内部代码只有一行可以省略 return和大括号{} 多行则不能省略

x => {
  if (x > 0) {
    return x * x;
  }
  else {
    return - x * x;
  }
}

如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

// SyntaxError:
            x => { foo: x }
            因为和函数体的{ ... }有语法冲突,所以要改为:
// ok:
            x => ({ foo: x })

二、this指向

1. 箭头函数this为父作用域的this,不是调用时的this

箭头函数内的this值继承自外围作用域。运行时它会首先到它的父作用域找,如果父作用域还是箭头函数,那么接着向上找,直到找到我们要的this指向。

我们先看一道经典的关于this的面试题:

var name = 'leo';
var teacher = {
  name: "大彬哥",
  showName: function () {
    function showTest() {
      alert(this.name);
    }
    showTest();
  }
};
teacher.showName();//结果是 leo,而我们期待的是大彬哥,这里this指向了window,我们期待指向teacher

大家知道,ES5中的this说好听了叫"灵活",说不好听就是瞎搞,特别容易出问题.而且面试还非常爱考,工作更不用说了,经常给我们开发捣乱,出现不好调试的bug,用E箭头函数解决这个问题就很得心应手了。

var name = 'leo';
var teacher = {
  name: "大彬哥",
  showName: function () {
    let showTest = ()=>alert(this.name);
    showTest();
  }
};
teacher.showName();

2. 任何方法都改变不了,包括call,apply,bind。

箭头函数中的this其实是父级作用域中的this。箭头函数引用了父级的变量词法作用域就是一个变量的作用在定义的时候就已经被定义好,当在本作用域中找不到变量,就会一直向父作用域中查找,直到找到为止。

由于this在箭头函数中已经按照词法作用域绑定了,所以,用call或者apply调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

var obj = {
  birth: 1996,
  getAge: function (year) {
    var b = this.birth; // 1996
    var fn = (y) => y - this.birth; // this.birth仍是1996
    return fn.call({birth:1990}, year);
  }
};
obj.getAge(2018); // 22 ( 2018 - 1996)

由于this已经在词法层面完成了绑定,通过call或apply方法调用一个函数时,只是传入了参数而已,对this并没有什么影响 。因此,这个设计节省了开发者思考上下文绑定的时间。

3. 箭头函数没有 arguments

箭头函数不仅没有this,常用的arguments也没有。如果你能获取到arguments,那它 一定是来自父作用域的。

function foo() {
  return () => console.log(arguments)
}

foo(1, 2)(3, 4)  // 1,2

上例中如果箭头函数有arguments,就应该输出的是3,4而不是1,2。 箭头函数不绑定arguments,取而代之用rest参数…解决

var foo = (...args) => {
  return args
}

console.log(foo(1,3,56,36,634,6))    // [1, 3, 56, 36, 634, 6]

箭头函数要实现类似纯函数的效果,必须剔除外部状态。我们可以看出,箭头函数除了传入的参数之外,真的在普通函数里常见的this、arguments、caller是统统没有的!

如果你在箭头函数引用了this、arguments或者参数之外的变量,那它们一定不是箭头函数本身包含的,而是从父级作用域继承的。

4. 箭头函数中不能使用 new

let Person = (name) => {
  this.name = name;
};
let one = new Person("galler");

运行该程序,则出现TypeError: Person is not a constructor

5. 箭头函数没有原型属性

var foo = () => {};
console.log(foo.prototype) //undefined

总结

  • 箭头函数this为父作用域的this,不是调用时的this
  • 箭头函数的this永远指向其父作用域,任何方法都改变不了,包括call,apply,bind。
  • 箭头函数不能作为构造函数,不能使用new,
  • 箭头函数没有arguments,caller,callee
  • 箭头函数没有原型属性