As 'Funções de seta' e 'Funções' são equivalentes / intercambiáveis?

Dec 19 2015

As funções de seta no ES2015 fornecem uma sintaxe mais concisa.

  • Posso substituir todas as minhas declarações / expressões de função por funções de seta agora?
  • O que devo procurar?

Exemplos:

Função construtora

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

Métodos de protótipo

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

Métodos de objeto (literal)

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

Callbacks

setTimeout(function() {
  // ...
}, 500);

// vs

setTimeout(() => {
  // ...
}, 500);

Funções variáveis

function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// vs
const sum = (...args) => {
  // ...
};

Respostas

817 FelixKling Dec 19 2015 at 00:58

tl; dr: Não! Funções de seta e declarações / expressões de função não são equivalentes e não podem ser substituídas às cegas.
Se a função que deseja substituir se não usar this, argumentse não é chamado com new, então sim.


Como sempre: depende . As funções de seta têm um comportamento diferente das declarações / expressões de função, então vamos dar uma olhada nas diferenças primeiro:

1. Lexical thisearguments

As funções de seta não têm funções próprias thisou argumentsvinculativas. Em vez disso, esses identificadores são resolvidos no escopo léxico como qualquer outra variável. Isso significa que dentro de uma função de seta thise se argumentsreferem aos valores de thise argumentsno ambiente em que a função de seta é definida (ou seja, "fora" da função de seta):

// Example using a function expression
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: function() {
      console.log('Inside `bar`:', this.foo);
    },
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

No caso da expressão de função, thisrefere-se ao objeto que foi criado dentro do createObject. No caso função seta, thisrefere-se a thisde createObjectsi.

Isso torna as funções de seta úteis se você precisar acessar o thisdo ambiente atual:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

Observe que isso também significa que não é possível definir uma função de seta thiscom .bindou .call.

Se você não estiver muito familiarizado com this, considere ler

2. As funções de seta não podem ser chamadas com new

ES2015 distingue entre funções que podem ser chamadas e funções que podem ser construídas . Se uma função é construtível, ela pode ser chamada com new, ie new User(). Se uma função pode ser chamada, ela pode ser chamada sem new(isto é, chamada de função normal).

As funções criadas por meio de declarações / expressões de função podem ser construídas e chamadas.
Funções de seta (e métodos) só podem ser chamadas. classconstrutores são apenas construtíveis.

Se você estiver tentando chamar uma função não chamável ou construir uma função não construtível, você obterá um erro de tempo de execução.


Sabendo disso, podemos afirmar o seguinte.

Substituível:

  • Funções que não usam thisou arguments.
  • Funções que são usadas com .bind(this)

Não substituível:

  • Funções de construtor
  • Função / métodos adicionados a um protótipo (porque eles geralmente usam this)
  • Funções variáveis ​​(se usarem arguments(veja abaixo))

Vamos dar uma olhada nisso usando seus exemplos:

Função construtora

Isso não funcionará porque as funções de seta não podem ser chamadas com new. Continue usando uma declaração / expressão ou uso de função class.

Métodos de protótipo

Provavelmente não, porque os métodos de protótipo geralmente são usados thispara acessar a instância. Se eles não usarem this, você pode substituí-lo. No entanto, se você se preocupa principalmente com a sintaxe concisa, use classcom sua sintaxe de método concisa:

class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name;
  }
}

Métodos de objeto

Da mesma forma para métodos em um literal de objeto. Se o método quiser fazer referência ao próprio objeto por meio de this, continue usando expressões de função ou use a nova sintaxe do método:

const obj = {
  getName() {
    // ...
  },
};

Callbacks

Depende. Definitivamente, você deve substituí-lo se estiver criando um alias para o externo thisou usando .bind(this):

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

Mas: Se o código que chama o retorno de chamada definir explicitamente thisum valor específico, como costuma ser o caso com manipuladores de eventos, especialmente com jQuery, e o retorno de chamada usar this(ou arguments), você não pode usar uma função de seta!

Funções variáveis

Como as funções de seta não têm funções próprias arguments, você não pode simplesmente substituí-las por uma função de seta. No entanto, o ES2015 apresenta uma alternativa ao uso arguments: o parâmetro rest .

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

Questão relacionada:

Outros recursos:

17 Ashutosh Jan 10 2020 at 03:22

Funções de seta => melhor recurso ES6 até agora. Eles são uma adição tremendamente poderosa ao ES6, que eu uso constantemente.

Espere, você não pode usar a função de seta em todo o seu código, não vai funcionar em todos os casos, como thisquando as funções de seta não são utilizáveis. Sem dúvida, a função arrow é um ótimo complemento pois traz simplicidade de código.

Mas você não pode usar uma função de seta quando um contexto dinâmico é necessário: definir métodos, criar objetos com construtores, obter o alvo disso ao lidar com eventos.

As funções de seta NÃO devem ser usadas porque:

  1. Eles não tem this

    Ele usa “escopo léxico” para descobrir qual thisdeve ser o valor de “ ”. No escopo lexical de palavras simples, ele usa “ this” de dentro do corpo da função.

  2. Eles não tem arguments

    As funções de seta não têm um argumentsobjeto. Mas a mesma funcionalidade pode ser alcançada usando os parâmetros de repouso.

    let sum = (...args) => args.reduce((x, y) => x + y, 0) sum(3, 3, 1) // output - 7 `

  3. Eles não podem ser usados ​​com new

    As funções de seta não podem ser construtoras porque não têm uma propriedade de protótipo.

Quando usar a função de seta e quando não:

  1. Não use para adicionar função como uma propriedade no literal do objeto porque não podemos acessar isso.
  2. Expressões de função são melhores para métodos de objeto. Arrow funções são melhores para callbacks ou métodos como map, reduceou forEach.
  3. Use declarações de função para funções que você chamaria por nome (porque elas são içadas).
  4. Use funções de seta para callbacks (porque eles tendem a ser mais curtos).
2 toddmo May 16 2020 at 08:56

Para usar as funções de seta function.prototype.call, criei uma função auxiliar no protótipo do objeto:

  // Using
  // @func = function() {use this here} or This => {use This here}
  using(func) {
    return func.call(this, this);
  }

uso

  var obj = {f:3, a:2}
  .using(This => This.f + This.a) // 5

Editar

Você NÃO PRECISA de um ajudante. Você poderia fazer:

var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5