什么场景不适合箭头函数

更新日期: 2020-02-24阅读: 1.6k标签: 函数

这些年来,ES6 将 JS 的可用性提升到一个新的水平时: 箭头函数、类等等,这些都很棒。

箭头函数是最有价值的新功能之一,有很多好文章描述了它的上下文透明性和简短的语法

但每个事务都有两面。通常,新特性会带来一些混乱,其中之一就是箭头函数被误导了。本文将介绍一些场景,在这些场景中,你应该绕过箭头函数,转而使用良好的旧函数表达式或较新的简写语法。并且要注意缩短代码,因为这会影响代码的可读性。


1.定义对象上的方法

在JS中,方法是存储在对象属性中的函数。当调用该方法时,this 将指向该方法所属的对象。

Object literal

由于箭头函数语法简短,所以使用它来定义方法是很有吸引力的,让咱们来试一试:

const calculate = {
  array: [1, 2, 3],
  sum: () => {
    console.log(this === window); // => true
    return this.array.reduce((result, item) => result + item);
  }
};
console.log(this === window); // => true
// Throws "TypeError: Cannot read property 'reduce' of undefined"
calculate.sum();

calculate.sum方法用箭头函数定义。 但是在调用时,calculate.sum() 会抛出一个TypeError,因为this.array 为undefined。

当调用calculate对象上的方法sum()时,上下文仍然是 window。之所以会发生这种情况,是因为箭头函数按词法作用域将上下文绑定到 window 对象。

执行this.array等同于window.array,它是undefined。

解决方法是使用常规函数表达式来定义方法。 this 是在调用时确定的,而不是由封闭的上下文决定的,来看看修复后的版本:

const calculate = {  
  array: [1, 2, 3],
  sum() {
    console.log(this === calculate); // => true
    return this.array.reduce((result, item) => result + item);
  }
};
calculate.sum(); // => 6

因为sum是常规函数,所以在调用 calculate.sum() 时 this 是 calculate 对象。 this.array是数组引用,因此正确计算元素之和:6。

Object prototype

同样的规则也适用于在原型对象上定义方法。使用一个箭头函数来定义sayCatName方法,this 指向 window

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

使用早期的方式定义函数表达式:

function MyCat(name) {
  this.catName = name;
}
MyCat.prototype.sayCatName = function() {
  console.log(this === cat); // => true
  return this.catName;
};
const cat = new MyCat('Mew');
cat.sayCatName(); // => 'Mew'

sayCatName常规函数在作为方法调用时将上下文更改为cat对象:cat.sayCatName()。


2. 动态上下文的回调函数

this 在JS中是一个强大的特性,它允许根据调用函数的方式更改上下文。通常,上下文是调用发生的目标对象,这使得代码更加自然,就像这个对象发生了什么。

但是,箭头函数会在声明上静态绑定上下文,并且无法使其动态化,但这种方式有坏也有好,有时候我们需要动态绑定。

在客户端编程中,将事件侦听器附加到dom元素是一项常见的任务。事件触发处理程序函数,并将this作为目标元素,这里如果使用箭头函数就不够灵活。

下面的示例尝试为这样的处理程序使用箭头函数:

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

在全局上下文中 this 指向 window。 当发生单击事件时,浏览器尝试使用按钮上下文调用处理函数,但箭头函数不会更改其预定义的上下文。this.innerHTML相当于window.innerHTML,没有任何意义。

必须应用函数表达式,该表达式允许根据目标元素更改 this:

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

当用户单击按钮时,处理程序函数中的 this 指向 button。因此这个问题。innerHTML = 'Clicked button' 正确地修改按钮文本以反映已单击状态。


3.调用构造函数

this 在构造调用中是新创建的对象。当执行new MyFunction()时,构造函数MyFunction的上下文是一个新对象:this instanceof MyFunction === true。

注意,箭头函数不能用作构造函数。 JavaScript通过抛出异常隐式阻止这样做。

无论如何,this是来自封闭上下文的设置,而不是新创建的对象。换句话说,箭头函数构造函数调用没有意义,而且是模糊的。

让我们看看如果尝试这样做会发生什么:

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

执行new Message('Hello World!'),其中Message是一个箭头函数,JavaScript抛出一个 TypeError 错误,Message不能用作构造函数。

上面的例子可以使用函数表达式来修复,这是创建构造函数的正确方法(包括函数声明):

const Message = function(text) {
  this.text = text;
};
const helloMessage = new Message('Hello World!');


简写语法

箭头函数有一个很好的属性,它可以省略参数圆括号()、块大括号{},如果函数主体只有一条语句,则返回。这有助于编写非常短的函数。

原文作者的大学编程教授给学生一个有趣的任务:编写 用C语言计算字符串长度的最短函数,这是学习和探索新语言的好方式。

然而,在实际应用程序中,许多开发人员都会阅读代码。 最短的语法并不总是适合帮助你的同事即时了解该方法的用途。

在某种程度上,简写的函数变得难以阅读,所以尽量不要过度使用。让各位们看一个例子

const multiply = (a, b) => b === undefined ? b => a * b : a * b;
const double = multiply(2);
double(3);      // => 6
multiply(2, 3); // => 6

multiply返回两个数字的乘法结果或与第一个参数绑定的闭包,以便以后的乘法运算。

该函数运行良好,看起来很短。但从一开始就很难理解它是做什么的。

为了使其更具可读性,可以从箭头函数恢复可选花括号和return语句,或使用常规函数:

function multiply(a, b) {
  if (b === undefined) {
    return function(b) {
      return a * b;
    }
  }
  return a * b;
}
const double = multiply(2);
double(3);      // => 6
multiply(2, 3); // => 6

在简短和冗长之间找到一个平衡点是很好的,这样可以使代码更加直观。


总结

毫无疑问,箭头函数是一个很好的补充。当正确使用时,它会使前面必须使用.bind()或试图捕获上下文的地方变得简单,它还简化了代码。

某些情况下的优点会给其他情况带来不利。 当需要动态上下文时,不能使用箭头函数:定义方法,使用构造函数创建对象,在处理事件时从 this 获取目标。

原文:https://dmitripavlutin.com/


链接: https://www.fly63.com/article/detial/9132

JavaScript 函数式编程

我理解的 JavaScript 函数式编程,都认为属于函数式编程的范畴,只要他们是以函数作为主要载体的。

Js函数式编程,给你的代码增加一点点函数式编程的特性

给你的代码增加一点点函数式编程的特性,最近我对函数式编程非常感兴趣。这个概念让我着迷:应用数学来增强抽象性和强制纯粹性,以避免副作用,并实现代码的良好可复用性。同时,函数式编程非常复杂。

让我们来创建一个JavaScript Wait函数

Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。

JavaScript函数创建的细节

如果你曾经了解或编写过JavaScript,你可能已经注意到定义函数的方法有两种。即便是对编程语言有更多经验的人也很难理解这些差异。在这篇博客的第一部分,我们将深入探讨函数声明和函数表达式之间的差异。

编写小而美函数的艺术

随着软件应用的复杂度不断上升,为了确保应用稳定且易拓展,代码质量就变的越来越重要。不幸的是,包括我在内的几乎每个开发者在职业生涯中都会面对质量很差的代码。这些代码通常有以下特征:

javascript回调函数的理解和使用方法(callback)

在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。

js调用函数的几种方法_ES5/ES6的函数调用方式

这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。

JavaScript中函数的三种定义方法

函数的三种定义方法分别是:函数定义语句、函数直接量表达式和Function()构造函数的方法,下面依次介绍这几种方法具体怎么实现,在实际编程中,Function()构造函数很少用到,前两中定义方法使用比较普遍。

js在excel的编写_excel支持使用JavaScript自定义函数编写

微软 称excel就实现面向开发者的功能,也就是说我们不仅可以全新定义的公式,还可以重新定义excel的内置函数,现在Excel自定义函数增加了使用 JavaScript 编写的支持,下面就简单介绍下如何使用js来编写excel自定义函数。

js中的立即执行函数的写法,立即执行函数作用是什么?

这篇文章主要讲解:js立即执行函数是什么?js使用立即执行函数有什么作用呢?js立即执行函数的写法有哪些?

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!