箭头函数特点

this指向

普通函数 this 永远指向函数的调用者。(注意匿名函数)
箭头函数中,this指向的是定义时所在的对象,而不是使用时所在的对象。箭头函数中不会创建自己的this,而是会从自己作用域链的上一层继承this。

  1. function Timer() {
  2. this.s1 = 0;
  3. this.s2 = 0;
  4. setInterval(() => this.s1++, 1000); // 箭头函数没有自己的this,会从自己作用域链的上一层继承this。此时this指向Timer
  5. setInterval(function () {
  6. this.s2++; // 在普通函数中,此时this指向window
  7. }, 1000);
  8. }
  9. let timer = new Timer();
  10. setTimeout(() => console.log('s1: ', timer.s1), 3100); // 3.1秒后输出s1: 3
  11. setTimeout(() => console.log('s2: ', timer.s2), 3100); // 3.1秒后输出s2: 0
  12. const Person = {
  13. 'name': 'kingx',
  14. 'age': 18,
  15. 'sayHello': function () { // sayHello()函数中的this会指向函数的调用体,即Person本身
  16. setTimeout(() => {
  17. console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
  18. }, 1000);
  19. }
  20. };
  21. Person.sayHello(); // 我叫kingx,我今年18岁!
  22. const Person2 = {
  23. 'name': 'little bear',
  24. 'age': 18,
  25. 'sayHello': () => { // sayHello()函数中的this会指向外层作用域,而Person2的父作用域就是全局作用域window
  26. setTimeout(() => {
  27. console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
  28. }, 1000);
  29. }
  30. };
  31. Person2.sayHello(); // 我叫undefined,我今年undefined岁!

不支持call()、apply()

原因:调用call()函数与apply()函数可以改变一个函数的执行主体,即改变被调用函数中this的指向。但是箭头函数却不能达到这一点,因为箭头函数并没有自己的this,而是继承父作用域中的this。

  1. let adder = {
  2. base: 1,
  3. add: function (a) {
  4. var f = (v) => v + this.base
  5. return f(a)
  6. },
  7. addThruCall: function (a) {
  8. var b = {
  9. base: 2,
  10. }
  11. var f = (v) => v + this.base
  12. return f.call(b, a) // 并不会改变箭头函数f中this的指向,this仍然指向adder,而且会接收参数a,b没有任何作用被忽略掉
  13. },
  14. }
  15. console.log(adder.add(1)) // 2
  16. console.log(adder.addThruCall(1)) // 2

不绑定arguments

在普通的function()函数中,可以通过arguments对象来获取到实际传入的参数值。
但是在箭头函数中,却无法做到这一点,同样也就无法使用caller和callee属性。

  1. const fn = () => {
  2. console.log(arguments);
  3. };
  4. fn(1, 2); // Uncaught ReferenceError: arguments is not defined

虽然无法通过arguments来获取实参,但是可以借助rest运算符(…)来达到这个目的。

  1. const fn = (...args) => {
  2. console.log(args);
  3. };
  4. fn(1, 2); // [1, 2]

支持嵌套

  1. const pipeline = (...funcs) => (val) => funcs.reduce((a, b) => b(a), val) // 返回一个函数
  2. const plus1 = (a) => a + 1
  3. const mult2 = (a) => a * 2
  4. const addThenMult = pipeline(plus1, mult2)
  5. addThenMult(5) // 相当于pipeline(plus1, mult2)(5) 12

箭头函数不适用场景

不适合作为对象的函数

如果使用箭头函数定义对象字面量的函数,那么其中的this将会指向外层作用域,并不会指向对象本身,因此箭头函数并不适合作为对象的函数。

  1. const Person2 = {
  2. 'name': 'little bear',
  3. 'age': 18,
  4. 'sayHello': () => { // sayHello()函数中的this会指向外层作用域,而Person2的父作用域就是全局作用域window
  5. setTimeout(() => {
  6. console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
  7. }, 1000);
  8. }
  9. };
  10. Person2.sayHello(); // 我叫undefined,我今年undefined岁!

不能作为构造函数,不能使用new操作符

构造函数是通过new操作符生成对象实例的,生成实例的过程也是通过构造函数给实例绑定this的过程,而箭头函数没有自己的this。因此不能使用箭头函数作为构造函数,也就不能通过new操作符来调用箭头函数。

  1. // 普通函数
  2. function Person(name) {
  3. this.name = name;
  4. }
  5. var p = new Person('kingx'); // 正常
  6. // 箭头函数
  7. let Person = (name) => {
  8. this.name = name
  9. };
  10. let p = new Person('kingx'); // Uncaught TypeError: Person is not a constructor

没有prototype属性

因为在箭头函数中是没有this的,也就不存在自己的作用域,因此箭头函数是没有prototype属性的。

  1. let a = () => {
  2. return 1;
  3. };
  4. function b(){
  5. return 2;
  6. }
  7. console.log(a.prototype); // undefined
  8. console.log(b.prototype); // {constructor: ƒ}

不能将原型函数定义成箭头函数

在给构造函数添加原型函数时,如果使用箭头函数,其中的this会指向全局作用域window,而并不会指向构造函数,因此并不会访问到构造函数本身,也就无法访问到实例属性,这就失去了作为原型函数的意义。

  1. function Person(name) {
  2. this.name = name
  3. }
  4. Person.prototype.sayHello = () => {
  5. console.log(this); // window
  6. console.log(this.name); // undefined
  7. };
  8. let p1 = new Person('kingx');
  9. p1.sayHello();