Czy „Funkcje strzałek” i „Funkcje” są równoważne / wymienne?

Dec 19 2015

Funkcje strzałek w ES2015 zapewniają bardziej zwięzłą składnię.

  • Czy mogę teraz zastąpić wszystkie deklaracje / wyrażenia funkcji funkcjami strzałkowymi?
  • Na co mam uważać?

Przykłady:

Funkcja konstruktora

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

// vs

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

Metody prototypowe

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

// vs

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

Metody obiektowe (dosłowne)

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

// vs

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

Callback

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

// vs

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

Funkcje wariadyczne

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

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

Odpowiedzi

817 FelixKling Dec 19 2015 at 00:58

tl; dr: Nie! Funkcje strzałkowe i deklaracje / wyrażenia funkcji nie są równoważne i nie można ich zastąpić ślepo.
Jeśli funkcja chcesz zastąpić ma nie używać this, argumentsa nie jest wywołana new, to tak.


Jak to często bywa: to zależy . Funkcje strzałkowe zachowują się inaczej niż deklaracje / wyrażenia funkcji, więc najpierw spójrzmy na różnice:

1. Leksykalne thisiarguments

Funkcje strzałkowe nie mają własnego thisani argumentspowiązania. Zamiast tego te identyfikatory są rozwiązywane w zakresie leksykalnym, jak każda inna zmienna. Oznacza to, że wewnątrz funkcji strzałkowej thisi argumentsodnoszą się do wartości thisoraz argumentsw środowisku funkcja strzałkowa jest zdefiniowana w (tj. „Na zewnątrz” funkcji strzałkowej):

// 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

W przypadku wyrażenia funkcji thisodnosi się do obiektu, który został utworzony wewnątrz createObject. W przypadku funkcji strzałki, thisodnosi się thisod createObjectsiebie.

Dzięki temu funkcje strzałek są przydatne, jeśli chcesz uzyskać dostęp thisdo bieżącego środowiska:

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

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

Zauważ, że oznacza to również, że nie można ustawić funkcji strzałek za thispomocą .bindlub .call.

Jeśli nie jesteś zbyt zaznajomiony this, rozważ przeczytanie

2. Funkcje strzałkowe nie mogą być wywoływane za pomocą new

ES2015 rozróżnia funkcje, które można wywoływać i funkcje, które można konstruować . Jeśli funkcję można konstruować, można ją wywołać za pomocą new, np new User(). Jeśli funkcja jest wywoływalna, można ją wywołać bez new(tj. Normalne wywołanie funkcji).

Funkcje utworzone za pomocą deklaracji / wyrażeń funkcji są zarówno konstruowalne, jak i wywoływalne.
Funkcje (i metody) strzałek można wywołać tylko. classkonstruktorów można tylko konstruować.

Jeśli próbujesz wywołać funkcję, której nie można wywołać lub skonstruować funkcję, której nie można skonstruować, pojawi się błąd w czasie wykonywania.


Wiedząc o tym, możemy stwierdzić, co następuje.

Wymienny:

  • Funkcje, które nie używają thislub arguments.
  • Funkcje używane z platformami .bind(this)

Nie wymienny:

  • Funkcje konstruktora
  • Funkcja / metody dodane do prototypu (ponieważ zwykle używają this)
  • Funkcje wariadyczne (jeśli używają arguments(patrz poniżej))

Przyjrzyjmy się temu bliżej na przykładach:

Funkcja konstruktora

To nie zadziała, ponieważ nie można wywołać funkcji strzałkowych new. Nadal używaj deklaracji / wyrażenia funkcji lub użyj class.

Metody prototypowe

Najprawdopodobniej nie, ponieważ metody prototypowe zwykle używają thisdo uzyskania dostępu do instancji. Jeśli nie używają this, możesz go wymienić. Jeśli jednak zależy Ci przede wszystkim na zwięzłej składni, użyj classjej zwięzłej składni metody:

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

Metody obiektowe

Podobnie dla metod w literale obiektu. Jeśli metoda chce odwołać się do samego obiektu za pośrednictwem this, nadal używaj wyrażeń funkcyjnych lub użyj nowej składni metody:

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

Callback

To zależy. Zdecydowanie powinieneś go wymienić, jeśli używasz aliasingu zewnętrznego thislub używasz .bind(this):

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

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

Ale: Jeśli kod, który wywołuje wywołanie zwrotne, jawnie ustawia thisokreśloną wartość, jak to często ma miejsce w przypadku programów obsługi zdarzeń, szczególnie w przypadku jQuery, a wywołanie zwrotne używa this(lub arguments), nie można użyć funkcji strzałki!

Funkcje wariadyczne

Ponieważ funkcje strzałkowe nie mają własnych arguments, nie można ich po prostu zastąpić funkcją strzałkową. Jednak ES2015 wprowadza alternatywę użycia arguments: parametr rest .

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

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

Powiązane pytanie:

Dalsze zasoby:

17 Ashutosh Jan 10 2020 at 03:22

Funkcje strzałek => najlepsza jak dotąd funkcja ES6. Są niesamowicie potężnym dodatkiem do ES6, z którego stale korzystam.

Czekaj, nie możesz używać funkcji strzałkowej wszędzie w kodzie, nie będzie ona działać we wszystkich przypadkach, takich jak thistam, gdzie funkcje strzałkowe nie będą użyteczne. Bez wątpienia funkcja strzałki jest świetnym dodatkiem, który upraszcza kod.

Ale nie możesz użyć funkcji strzałki, gdy wymagany jest dynamiczny kontekst: definiowanie metod, tworzenie obiektów za pomocą konstruktorów, pobieranie celu podczas obsługi zdarzeń.

Funkcje strzałkowe NIE powinny być używane, ponieważ:

  1. Oni nie mają this

    Używa „leksykalnego zakresu”, aby dowiedzieć się, jaka thispowinna być wartość „ ”. W prostym słowie zakres leksykalny wykorzystuje „ this” z wnętrza ciała funkcji.

  2. Oni nie mają arguments

    Funkcje strzałkowe nie mają argumentsobiektu. Ale tę samą funkcjonalność można osiągnąć za pomocą parametrów odpoczynku.

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

  3. Nie można ich używać z new

    Funkcje strzałkowe nie mogą być konstruktorami, ponieważ nie mają właściwości prototypu.

Kiedy używać funkcji strzałek, a kiedy nie:

  1. Nie używaj funkcji dodawania funkcji jako właściwości w literale obiektu, ponieważ nie mamy do niej dostępu.
  2. Wyrażenia funkcyjne są najlepsze dla metod obiektowych. Strzałka funkcje są najlepsze dla wywołania zwrotne lub metod, takich jak map, reducelub forEach.
  3. Użyj deklaracji funkcji dla funkcji, które chcesz wywołać według nazwy (ponieważ są one podniesione).
  4. Użyj funkcji strzałek do wywołań zwrotnych (ponieważ są one zwykle bardziej zwięzłe).
2 toddmo May 16 2020 at 08:56

Aby używać funkcji strzałkowych function.prototype.call, utworzyłem funkcję pomocniczą na prototypie obiektu:

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

stosowanie

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

Edytować

NIE POTRZEBUJESZ pomocnika. Mógłbyś:

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