10分钟理解ES6箭头函数

10分钟理解ES6箭头函数前言面试中 ES6 是一大考点 当被问到箭头函数时 我们都会说 箭头函数很好用 而且再也不用操心 this 的指向了 面试官 箭头函数是挺好用的 那有哪些不适合使用箭头函数的场景呢 箭头函数在大多数情况下 是很好用的 但是为什么在有些场景 使用箭头函数后会产生问题 是不是箭头函数还不够完善 又有哪些场景会发生问题 该如何解决呢 为了防止血案的产生 重新吧这一块拎出来整理巩固一下 概念 ES6 允许使用箭头 gt 定义函数 箭头函数提供了一种更加简洁的函数书写方式 箭头函数多用于匿名函数的定

前言

箭头函数在大多数情况下,是很好用的,但是为什么在有些场景,使用箭头函数后会产生问题?是不是箭头函数还不够完善?又有哪些场景会发生问题?该如何解决呢?为了防止血案的产生,重新吧这一块拎出来整理巩固一下。

概念

ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义

箭头函数的注意点:

  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,并省略return,函数的返回值为该条语句的执行结果;
  3. 箭头函数 this 指向声明时所在作用域下 this 的值;
  4. 箭头函数不能作为构造函数实例化;
  5. 不能使用 arguments;

特性

  1. 箭头函数的this是静态的始终指向函数声明时所在作用域下的this的值;
  2. 不能作为构造实例化对象;
  3. 不能使用 arguments 变量;

箭头函数的写法

为什么叫箭头函数( Arrow Function )?因为它的写法,看上去就是一个箭头:

const multiply = num => num * num; 

它等价于:

const multiply = function (num) { 
    return num * num; }; 

此外,还可以传多个参数,以及可变参数。

// 多参数 const multiply = (num1, num2) => num1 * num2; // 可变参数 const sum = (num1, num2, ...rest) => { 
    let result = num1 + num2; for (let i = 0; i < rest.length; i++) { 
    result += rest[i]; } return result; }; 

当有多条语句时,需要配上 {...}return

另外,如果返回的结果是对象,则需要配上 (),像下面这样:

const func = val => ({ 
    value: val }); 

从上述的写法来看,相较普通函数而言,箭头函数的确简便了很多,提升了我们代码的易用性。但它并非在任何场景下都适用,接下来,将会介绍几种不适合箭头函数的场景,并会提出可行的解决方案。

不适合的场景

1、对象的方法

看下面这个例子:

const obj = { 
    x: 1, print: () => { 
    console.log(this === window); // => true console.log(this.x); // undefined } }; obj.print(); 

this.x 打印出来是 undefined。为什么?然后,我在上面加了一行,发现 this 指向了 window。

解析:print 方法用了箭头函数,其内部的 this 指向的还是上下文 window,上下文中并没有定义 x,所以 this.x 输出为 undefined。

解决办法:用 ES6 的短语法,或者传统的函数表达式都可以。所以,print 要这样写:

print () { 
    console.log(this === test); // => true console.log(this.x); // 1 } 

2、原型方法

同样的规则也适用于原型方法的定义,使用箭头函数会导致运行时的执行上下文错误。

function Cat (name) { 
    this.name = name; } Cat.prototype.sayCatName = () => { 
    console.log(this === window); // => true return this.name; }; const cat = new Cat('Miao'); cat.sayCatName(); // => undefined 

解决办法是:用回传统的函数表达式,像下面这样:

Cat.prototype.sayCatName = function () { 
    console.log(this === cat); // => true return this.name; }; 

sayCatName 变回传统的函数表达式之后,被调用时的执行上下文就会指向新创建的 cat 实例。

3、事件的回调

看下面这个例子:

const btn = document.getElementById('myButton'); btn.addEventListener('click', () => { 
    console.log(this === window); // => true this.innerHTML = 'Clicked button'; }); 

这里会有问题,因为 this 指向了 window。

解析:当为一个 DOM 事件绑定回调函数后,触发回调函数时的 this,需要指向当前发生事件的 DOM 节点,也就是这里的 btn。当回调发生时,浏览器会用 btn 的上下文去调用处理函数。所以最后的 this.innerHTML 等价于 window.innerHTML,问题就在这里。

解决办法:用函数表达式代替箭头函数。像这样:

btn.addEventListener('click', function() { 
    console.log(this === btn); // => true this.innerHTML = 'Clicked button'; }); 

另外,在 react 中的事件回调,也经常会遇到类似的问题。

// jsx render <Button onClick={ 
       this.handleClickButton.bind(this)}> ...  
     Button> // callback handleClickButton () { ... } 

注意:这里 onClick 的回调函数,并非字符串,而是一个实实在在的函数。可以将 onClick 理解为一个中间变量,所以 react 在处理函数时的 this 指向就会丢失。

为了解决这个问题,我们需要为回调函数绑定 this,使得事件处理函数无论如何传递,this 都指向我们实例化的那个对象。

在这里,如果用箭头函数,可以这样改写:

 

箭头函数并没有自己的 this,所以事件处理函数的调用者并不受影响。

4、构造函数

箭头函数不能通过 new 关键字调用。

const Message = (text) => { 
    this.text = text; }; var helloMessage = new Message('Hello World!'); // Uncaught TypeError: Message is not a constructor 

解析:从报错信息可以看出,箭头函数没有 constructor 方法,所以不能用作构造函数。 JavaScript 会通过抛出异常的方式,进行隐式地预防。

解决方法:用函数表达式代替箭头函数。

总结

回顾 MDN 给出的解释:箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。

所以说,箭头函数无疑是 ES6 带来的重大改进,在正确的场合使用箭头函数,能让代码变得更加简洁短小。但箭头函数也不是万能的,不能用的时候,千万别硬往上套。比如,在需要动态上下文的场景中,使用箭头函数需要格外地小心,这些场景包括:对象的方法、原型方法、事件的回调、构造函数。并非一定要用箭头函数,才能解决问题。

  1. 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
  2. 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/211073.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午11:15
下一篇 2026年3月18日 下午11:16


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号