箭头函数

... 2022-12-19 About 4 min

# 箭头函数

箭头函数可以用于解决this混乱的问题,而this的问题在es5中真的是很让人恶心的东西

简写

  1. 如果有且仅有一个参数,()也可以不写
  2. 如果有且仅有一个语句,return,{}也可以不写

# 基本用法

let func = v => v
// <!-- <====> -->
function func(v){
  return v
}
1
2
3
4
5

如果箭头函数不需要参数或者需要多个参数,就可以

let sum = (a,b,c) => a+b+c
// ES5
function sum(a,b,c){
  return a+b+c
}
1
2
3
4
5

如果箭头函数的代码块多余一条语句,就要使用大括号将他们括起来,并且使用return语句返回

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

  let getTempItem = id => { id: id, name: "Temp" } // error
  // 正确的写法
  let getTempItem = id => ({ id: id, name: "Temp" })
  <!-- <====> -->
  function getTempItem (id) {
    return { id: id, name: "Temp" }
  }

  // 有一个特殊的情况需要注意,
  let foo = () => { a: 1 } // 不报错,但是得不到想要的值
  foo() // undefined
1
2
3
4
5
6
7
8
9
10
11

上面foo中,原始意图是返回一个对象{ a: 1 },但是由于引擎认为大括号是代码块,所以执行了一行语句a: 1。这时,a可以被解释为语句的标签,因此实际执行的语句是1;,然后函数就结束了,没有返回值。

至于() => {}的应用那就太多太多了,相信用过的话都应该会比较喜欢的

# 使用注意点

箭头函数使用又几个使用注意点

  1. 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,这一点很重要,在使用的时候这一点大多数时候会给你带来好处
  2. 不可以当作构造函数,也就是说,不可以使用new命名,否则会抛出错误
  3. 不可以使用arguments对象,该对象在函数体内不存在,如果要是使用,可以使用rest参数数组代替
  4. 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

解释一下上面的原因

  1. this对象的指向是可变的,但是在箭头函数中,它是固定的。
function foo() {
  setTimeout(() => {
    console.log('id:', this.id); // 这个地方this如果不使用call就是指向window,输出21
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
1
2
3
4
5
6
7
8
9
function Timer () {
  this.s1 = 0;
  this.s2 = 0;
  setInterval(() => this.s1++,1000) // 这段代码中,此处的this指向Timer的实例上的变量也就是timer
  setInterval(function(){
    this.s2++ // 这个地方的this指向window
  },1000)
}
var s2 = 0
var timer = new Timer()
setTimeout(() => {console.log(`s1: ${timer.s1}`),3100})
setTimeout(() => {console.log(`s2: ${timer.s2}`),3100}) // 打印的s2根本就没有走过第二个计时器
1
2
3
4
5
6
7
8
9
10
11
12
  1. 为什么() => {}不能作为构造函数,就是因为this的原因
let handle = {
  id:'asfhqj3rqlfhasldfqhl3r2q3jh4234',
  init:function () {
    document.addEventListener('click',event => this.doSomeThing(event.type)) // 这里的this指向handle,调用deSomeThing方法
  },
  doSomeThing: function (type) {
    console.log(`Handling ${type} for ${this.id}`)
  }
}
1
2
3
4
5
6
7
8
9

this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。这也是我们所说的this窜出去的原因

function foo(){
  return () => {
    return () => {
      return () => {
        console.log(`id: ${this.id}`)
      }
    }
  }
}
var f = foo.call({id:1}) // 对于f来讲就在此时此刻已经定下来this就是{id:123}

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就已经窜出去指向第一个f了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

除了this,还有三个变量在箭头函数之中也是不存在的 argumentssupernew.target

(function() {
  return [
    (() => this.x).bind({ x: 'inner' })()
    // (() => this.x))()
  ];
}).call({ x: 'outer' });
// ['outer']
1
2
3
4
5
6
7

上面的代码,因为箭头函数是没有this的,所以bind是没有效果的,this会窜出到return外面一层

# 不适合使用箭头函数的场合

  1. 定义对象的方法,不要使用箭头函数
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--; // 这个地方的this指向的是全局作用域
  }
}
1
2
3
4
5
6
  1. 需要动态this的时候,不要使用箭头函数
  var button = document.getElementById('press');
    button.addEventListener('click', () => {
    this.classList.toggle('on'); // 这个地方的this指向的是全局作用域,而不是button
  });
1
2
3
4

# 嵌套的箭头函数

箭头函数的嵌套我觉得就是书写简单,增强可读性,见仁见智吧

function insert(value) {
  return { into: function (arr) {
    return { after: function (afterValue) {
          arr.splice(arr.indexOf(afterValue + 1), 0, value)
          return arr
        }
      }
    }
  }
}
insert(2).into([1,3]).after(1) // [1,2,3]
1
2
3
4
5
6
7
8
9
10
11

使用es6的箭头函数的书写

let insert = value => ({
    into: arr => ({
        after: afterValue => {
          arr.splice(arr.indexOf(afterValue+1), 0, value)
          return arr
        }
      })
    })

insert(2).into([1,3]).after(1) // [1,2,3]
1
2
3
4
5
6
7
8
9
10

效果是一样的

管道pipeline机制

  const pipeline = (...funcs) =>
    val => funcs.reduce((a,b) => b(a),val)
  const plus1 = a => a + 1
  const plus2 = a => a * 2
  const add = pipeline(plus1,plus2)
  add(5) // 12
1
2
3
4
5
6

讲道理,上面的代码有点装X,下面的写法还是朴实无华的

const plus1 = a => a + 1
const plus2 = a => a * 2
const muilt = val => plus2(plus2(val))
1
2
3

接下来要说的与箭头函数无关,而是说的一种很高效的方法或者说模式吧

Last update: December 19, 2022 11:58
Contributors: salvatoreliaoxuan