10分钟理解ES6箭头函数
前言
面试中,ES6 是一大考点,当被问到箭头函数时,我们都会说:箭头函数很好用,而且再也不用操心 this 的指向了。
面试官:箭头函数是挺好用的,那有哪些不适合使用箭头函数的场景呢?
箭头函数在大多数情况下,是很好用的,但是为什么在有些场景,使用箭头函数后会产生问题?是不是箭头函数还不够完善?又有哪些场景会发生问题?该如何解决呢?为了防止血案的产生,重新吧这一块拎出来整理巩固一下。
概念
ES6允许使用
箭头(=>)定义函
数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义
;
箭头函数的注意点:
如果形参只有一个,则小括号可以省略;
函数体如果只有一条语句,则花括号可以省略,并省略return,函数的返回值为该条语句的执行结果;
箭头函数 this 指向声明时所在作用域下 this 的值;
箭头函数不能作为构造函数实例化;
不能使用 arguments;
特性
- 箭头函数的this
是静态的
,始终指向函数声明时所在作用域下的this
的值;- 不能作为构造实例化对象;
- 不能使用 arguments 变量;
箭头函数的写法
为什么叫箭头函数( Arrow Function )?因为它的写法,看上去就是一个箭头:
1 |
|
它等价于:
1 |
|
此外,还可以传多个参数,以及可变参数。
1 |
|
当有多条语句时,需要配上 {...}
和 return
。
另外,如果返回的结果是对象,则需要配上 ()
,像下面这样:
1 |
|
从上述的写法来看,相较普通函数而言,箭头函数的确简便了很多,提升了我们代码的易用性。但它并非在任何场景下都适用,接下来,将会介绍几种不适合箭头函数的场景,并会提出可行的解决方案。
不适合的场景
1、对象的方法
看下面这个例子:
1 |
|
this.x 打印出来是 undefined。为什么?然后,我在上面加了一行,发现 this 指向了 window。
解析:print 方法用了箭头函数,其内部的 this 指向的还是上下文 window,上下文中并没有定义 x,所以 this.x 输出为 undefined。
解决办法:用 ES6 的短语法,或者传统的函数表达式都可以。所以,print 要这样写:
1 |
|
2、原型方法
同样的规则也适用于原型方法的定义,使用箭头函数会导致运行时的执行上下文错误。
1 |
|
解决办法是:用回传统的函数表达式,像下面这样:
1 |
|
sayCatName 变回传统的函数表达式之后,被调用时的执行上下文就会指向新创建的 cat 实例。
3、事件的回调
看下面这个例子:
1 |
|
这里会有问题,因为 this 指向了 window。
解析:当为一个 DOM 事件绑定回调函数后,触发回调函数时的 this,需要指向当前发生事件的 DOM 节点,也就是这里的 btn。当回调发生时,浏览器会用 btn 的上下文去调用处理函数。所以最后的 this.innerHTML 等价于 window.innerHTML,问题就在这里。
解决办法:用函数表达式代替箭头函数。像这样:
1 |
|
另外,在 react 中的事件回调,也经常会遇到类似的问题。
1 |
|
注意:这里 onClick 的回调函数,并非字符串,而是一个实实在在的函数。可以将 onClick 理解为一个中间变量,所以 react 在处理函数时的 this 指向就会丢失。
为了解决这个问题,我们需要为回调函数绑定 this,使得事件处理函数无论如何传递,this 都指向我们实例化的那个对象。
在这里,如果用箭头函数,可以这样改写:
1 |
|
箭头函数并没有自己的 this,所以事件处理函数的调用者并不受影响。
4、构造函数
箭头函数不能通过 new 关键字调用。
1 |
|
解析:从报错信息可以看出,箭头函数没有 constructor 方法,所以不能用作构造函数。 JavaScript 会通过抛出异常的方式,进行隐式地预防。
解决方法:用函数表达式代替箭头函数。
总结
回顾 MDN 给出的解释:箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target
。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
所以说,箭头函数无疑是 ES6 带来的重大改进,在正确的场合使用箭头函数,能让代码变得更加简洁短小。但箭头函数也不是万能的,不能用的时候,千万别硬往上套。比如,在需要动态上下文的场景中,使用箭头函数需要格外地小心,这些场景包括:对象的方法、原型方法、事件的回调、构造函数。并非一定要用箭头函数,才能解决问题。
- 箭头函数适合与
this 无关的回调. 定时器, 数组的方法回调
- 箭头函数不适合与 this 有关的回调.
事件回调, 对象的方法