整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

编写高质量箭头函数的5个最佳做法

者:Dmitri Pavlutin译者:前端小智 来源:dmitripavlutin.com

箭头功能值得流行。它的语法简洁明了,使用词法绑定绑定 this,它非常适合作为回调。在本文中,通过了解决学习5个最佳实践,以便我们可以从中学习更多箭头函数的知识,并从它身上获得更多的好处。

1. 箭头函数名推断

JS 中的箭头函数是匿名(anonymous)的:函数的name属性是''。

( number => number + 1 ).name; // => ''

在调试会话或调用堆栈分析期间,匿名函数被标记为anonymous。不幸的是,anonymous程序不提供有关正在执行的代码的任何线索。

这里是执行匿名函数的代码的调试会话:

右边的调用堆栈由两个标记为anonymous的函数组成,我们无法从这样的调用堆栈信息中获得任何有用的信息。

幸运的是,函数名推断(ES2015的功能)可以在某些条件下检测到函数名称。名称推断的思想是JS 可以从其语法位置确定箭头函数名称:从保存函数对象的变量名称中获取。

我们来看看函数名称推断的工作原理:

const increaseNumber = number => number + 1;

increaseNumber.name; // => 'increaseNumber'

因为变量increaseNumber保存了箭头函数,所以 JS 决定使用increaseNumber作为该函数的名称。因此,箭头函数的名称为 'increaseNumber'。

第1个实践:

一个好的做法是使用函数名称推断来命名箭头函数。

现在我们用使用名称推断的代码检查一个调试会话:

因为箭头函数有名称,所以调用堆栈提供了有关正在执行的代码的更多信息。

  • handleButtonClick函数名称表示发生了单击事件
  • gainCounter增加一个计数器变量。

2.尽可能使用内联方式

内联函数是仅具有一个表达式的函数。我喜欢箭头功能,可以编写短内联函数。

例如,不要使用箭头函数的长形式:

const array = [1, 2, 3];

array.map((number) => { 
  return number * 2;
});

当箭头函数只有一个表达式时,可以轻松地删除大括号{}和return语句:

const array = [1, 2, 3];

array.map(number => number * 2);

第2个实践:

当函数只有一个表达式时,一个好的做法是使用内联箭头函数格式

3.胖箭头和比较运算符

比较操作符>、<、<=和>=看起来类似于f胖箭头=>(它定义了箭头函数)。当在内联箭头函数中使用这些比较操作符时,会产生一些混淆。

例如我们定义一个使用<=操作符的箭头函数

const negativeToZero = number => number <= 0 ? 0 : number;

同一行上的两个符号=>和<=的存在会引起误解。

为了清楚地将胖箭头与比较操作符区分开,我们可以使用圆括号:

const negativeToZero = number => (number <= 0 ? 0 : number);

第二个选项是使用更长的形式来定义箭头函数:

const negativeToZero = number => {
  return number <= 0 ? 0 : number;
};

这些重构消除了胖箭头符号和比较操作符之间的混淆。

第3个实践:

如果箭头函数包含操作符>、<、<=和>=,一个好的做法是将表达式包装成一对括号,或者故意使用更长的箭头函数形式。

4.构造普通对象

在内联箭头函数中使用对象字面量会触发语法错误:

const array = [1, 2, 3];

// throws SyntaxError!
array.map(number => { 'number': number });

JS 认为花括号是代码块,而不是对象文字。

将对象字面量加上一对括号即可解决此问题:

const array = [1, 2, 3];

// Works!
array.map(number => ({ 'number': number }));

如果对象字面量有很多属性,我们可以使用换行,同时仍然保持箭头函数内联

const array = [1, 2, 3];

// Works!
array.map(number => ({
  'number': number
  'propA': 'value A',
  'propB': 'value B'
}));

第4个实践:

在内联箭头函数中使用对象时,把改对象包装在一对括号中。

5.注意过多的嵌套

箭头函数的语法很短,很好。但是,副作用是,当许多箭头函数嵌套时,它可能是晦涩难懂。

我们考虑以下情况。单击按钮后,启动对服务器的请求,响应准备就绪后,将各项记录到控制台:

myButton.addEventListener('click', () => {
  fetch('/items.json')
    .then(response => response.json());
    .then(json => {
      json.forEach(item => {
        console.log(item.name);
      });
    });
});

这里有三层箭头函数的嵌套,需要花时间和精力来了解代码的作用。

为了提高嵌套函数的可读性,第一种方法是引入每个包含箭头函数的变量,该变量应简明地描述函数的功能。

const readItemsJson = json => {
  json.forEach(item => console.log(item.name));
};

const handleButtonClick = () => {
  fetch('/items.json')
    .then(response => response.json());
    .then(readItemsJson);
};

myButton.addEventListener('click', handleButtonClick);

重构将箭头函数提取到变量readItemsJson和handleButtonClick中。嵌套级别从3减少到2。现在,我们可以更轻松地了解脚本的功能。

更好的是,可以使用async/await语法重构整个函数,这是解决函数嵌套的一个很好的方法:

const handleButtonClick = async () => {
  const response = await fetch('/items.json');
  const json = await response.json();
  json.forEach(item => console.log(item.name));
};

myButton.addEventListener('click', handleButtonClick);

第5个实践:

避免箭头函数过多的嵌套,好的做法是通过将箭头函数提取为独立函数,或者尽可能使用async/await语法。

6. 总结

JS中的箭头函数是匿名的。为了使调试更高效,一个好的实践是使用变量来保存箭头函数,这允许JS 推断函数名。

当函数主体具有一个表达式时,嵌入式箭头函数非常方便。

操作符>、<、<=和>=看起来类似于胖箭头=>,在内联箭头函数中使用这些操作符时必须小心。

对象字面量语法{prop:'value'}与代码块{}相似。因此,当将对象字面量放置在嵌入式箭头函数中时,需要将其包装在一对括号中:()=>({prop:'value'})。

最后,函数的过度嵌套模糊了代码意图。减少箭头函数嵌套的一个好方法是将它们提取到变量中。或者,尝试使用更好的特性,如async/await语法。

对于箭头函数,你还有什么建议,欢迎留言讨论。


原文:https://dmitripavlutin.com/javascript-arrow-functions-best-practices/

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。为什么叫Arrow Function?

因为它的定义用的就是一个箭头:

x => x * x

示例相当于如下代码:

function (x) {
    return x * x;
}

JavaScript箭头函数是ECMAScript 6中引入的编写函数表达式的一种简便方法。

箭头函数的语法如下:

(parameters) => { statements }

如果没有参数,则表示一个箭头函数,如下所示:

() => { statements }

当您只有一个参数时,左括号是可选的:

parameters => { statements }

如果包含只返回返回表达式,请删除方括号:

parameters => expression


带来的好处

简洁的语法

让我们看一下常规函数:

function funcName(params) { 
  return params + 2; 
}
funcName(2); // 4

然后通过箭头函数精简之后为:

var funcName=params => params+2;
funcName(2); // 4

可以看到通过箭头函数实现之后,语法更加精简。

不绑定this

与常规函数不同,箭头函数不绑定this。相反,它是在词汇上绑定的(即this保持其原始上下文的含义)。

由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return 2020 - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

但是,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => 2020 - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 30

使用箭头函数的限制条件

应用箭头函数时要注意的一些限制条件:

  • 箭头函数没有参数对象。
  • 箭头函数不能与新运算符一起使用,因此它不能用作构造函数。
  • 箭头函数没有原型属性。
  • 如果你尝试使用箭头函数作为构造函数,那么你会得到异常。请看下面的代码:

    var foo = (name, age) => { name = name, age = age };
    var f1 = new foo("cat", 6);

    代码试图通过使用箭头函数foo作为构造函数来创建对象f1,JavaScript将抛出以下异常:

    而且,当你试图输出箭头函数的原型值时,你会得到undefined的输出:

    var foo = (name, age) => { name = name, age = age };
    console.log(foo.prototype);

    发生这种情况的原因是因为箭头函数没有原型属性。请记住:虽然箭头函数为你提供了编写函数表达式的简短方法,但它没有自己的this值,也不能用作构造函数。

    .上标

    n2=n+1

    在markdown中写法:

    n<sup>2</sup>=n+1
    

    2.下标

    a=log2b

    在markdown中写法:

    a=log<sub>2</sub>b
    

    3.特殊符号

    ® ⋚ ° ⪚ ≫ ≶ ƒ √ " &

    在markdown中写法:

    ®   ⋚  °  ⪚  ≫  ≶  ƒ  √  \"  \&
    

    居中::-:

    箭头符号:

    在markdown中写法:

    $\Rightarrow$  $\Leftarrow$
    

    4.空格

    在 Markdown 文档中,可以直接采用 HTML 标记插入空格(blank space),而且无需任何其他前缀或分隔符。具体如下所示:

    插入一个空格 或 或 (non-breaking space)

    插入两个空格  或 或 (en space)

    插入四个空格  或 或 (em space)

    插入细的空格  或 或 (thin space)

    在markdown中写法:

    插入一个空格
     或 或 
    插入两个空格
     或 或 
    插入四个空格
     或 或 
    插入细的空格
     或 或 
    

    注意:不要漏掉分号。