Czy "funkcje strzałek" i "funkcje" są równoważne / wymienne?

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

  • Czy mogę teraz zastąpić wszystkie deklaracje / wyrażenia funkcji funkcjami strzałek?
  • 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: () => {
    // ...
  }
};

Callbacks

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

// vs

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

Funkcje Zmienne

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

// vs
const sum = (...args) => {
  // ...
};
Author: jarmod, 2015-12-18

3 answers

Tl; dr: Nie! funkcje strzałek i deklaracje / wyrażenia funkcji nie są równoważne i nie można ich zastąpić na ślepo.
Jeśli funkcja, którą chcesz zastąpić, Nie , użyj this, arguments i nie jest wywoływana przez new, to tak.


Jak często: To zależy . Funkcje strzałek mają inne zachowanie niż deklaracje / wyrażenia funkcji, więc spójrzmy najpierw na różnice: {]}

1. Leksykalne this i arguments

Funkcje strzałek nie mają własnych wiązań this lub arguments. Zamiast tego identyfikatory te są rozwiązywane w zakresie leksykalnym, jak każda inna zmienna. Oznacza to, że wewnątrz funkcji strzałki, this i arguments odnoszą się do wartości this i arguments w środowisku funkcja strzałki jest zdefiniowana W (tzn. "na zewnątrz" funkcji strzałki):

// 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, this odnosi się do obiektu który powstał wewnątrz createObject. W przypadku funkcji strzałki, this odnosi się do this z createObject.

To sprawia, że funkcje strzałek są przydatne, jeśli potrzebujesz dostępu do this 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łki this za pomocą .bind lub .call.

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

2. Funkcji strzałek nie można wywoływać za pomocą new

ES2015 rozróżnia funkcje, które są call able i funkcje, które są construct able. Jeśli funkcja jest konstruktywna, można ją wywołać za pomocą new, tzn. new User(). Jeśli funkcja jest wywoływalna, może być wywołana bez new (tj. normalnego wywołania funkcji).

Funkcje tworzone przez deklaracje / wyrażenia funkcji są zarówno konstruktywne, jak i możliwe do wywołania.
Funkcje strzałek (i metody) można wywoływać tylko. class konstruktory są tylko konstruktywne.

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


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

  • funkcje, które nie używają this lub arguments.
  • funkcje, które są używane z .bind(this)

Nie "Type": "content"]}

  • funkcje konstruktora
  • funkcja / metody dodane do prototypu (ponieważ zwykle używają this)
  • Funkcje Zmienne (jeśli używają arguments (patrz niżej))

Przyjrzyjmy się temu bliżej, używając Twoich przykładów:

Funkcja konstruktora

To nie zadziała, ponieważ funkcje strzałek nie mogą być wywoływane przez new. Używaj deklaracji / wyrażenia funkcji lub użycia class.

Prototype metody

Najprawdopodobniej nie, ponieważ metody prototypowe zwykle używają this, aby uzyskać dostęp do instancji. Jeśli nie użyją this, możesz go zastąpić. Jeśli jednak zależy Ci przede wszystkim na zwięzłej składni, użyj class ze składnią zwięzłej metody:

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

Metody obiektowe

Podobnie dla metod w dosłownym obiekcie. Jeśli metoda chce odwoływać się do samego obiektu za pomocą this, należy używać wyrażeń funkcji lub użyć nowej metody składnia:

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

Callbacks

To zależy. Zdecydowanie powinieneś go zastąpić, jeśli aliasujesz zewnętrzną this lub używasz .bind(this):
// old
setTimeout(function() {
  // ...
}.bind(this), 500);

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

Ale: jeśli kod wywołujący wywołanie zwrotne jawnie ustawia this na określoną wartość, jak to często bywa w programach obsługi zdarzeń, zwłaszcza w jQuery, a wywołanie zwrotne używa this (lub arguments), nie można użyć funkcji strzałki!

Funkcje Zmienne

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

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

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

Podobne pytanie:

Dalsze zasoby:

 836
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-20 06:23:08

Arrow functions = > najlepsza jak dotąd funkcja ES6. Są ogromnie potężny dodatek do ES6, którego używam stale.

Czekaj, nie możesz używać funkcji strzałek wszędzie w kodzie, jej nie będzie działać we wszystkich przypadkach, takich jak this gdzie funkcje strzałek nie są użyteczne. Bez wątpienia funkcja arrow jest świetnym dodatkiem, który przynosi prostotę kodu.

Ale nie można użyć funkcji strzałki, gdy wymagany jest dynamiczny kontekst: definiowanie metod, tworzenie obiektów z konstruktorów, uzyskać cel z tego podczas obsługi zdarzeń.

Funkcje strzałek nie powinny być używane, ponieważ:

  1. Nie mają this

    Używa "zakresu leksykalnego", aby dowiedzieć się, jaka jest wartość " this" powinno być. W prostym słowniku leksykalnym używa się "this " z wewnątrz ciała funkcji.

  2. Nie mają arguments

    Funkcje strzałek nie mają obiektu arguments. Ale to samo funkcjonalność można osiągnąć za pomocą parametrów spoczynkowych.

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

  3. Nie mogą być używane z new

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

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

  1. nie używaj do dodawania funkcji jako właściwości obiektu, ponieważ nie mogę się do tego dostać.
  2. wyrażenia funkcyjne są najlepsze dla metod obiektowych. Funkcje strzałek są najlepsze dla wywołań zwrotnych lub metod takich jak map, reduce, lub forEach.
  3. użyj deklaracji funkcji dla funkcji, które wywołujesz po nazwie (ponieważ są wciągane).
  4. użyj funkcji strzałek dla wywołań zwrotnych (ponieważ mają tendencję do terser).
 19
Author: Ashutosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Aby użyć funkcji strzałek z function.prototype.call, wykonałem funkcję pomocniczą na prototypie obiektu:

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

Użycie

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

Edit

Nie potrzebujesz pomocnika. Można zrobić:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5
 2
Author: toddmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-16 02:23:29