Funkcje ES6, funkcje strzałek i "to" w klasie ES6 [duplikat]

to pytanie ma już odpowiedzi tutaj : Czy powinienem pisać metody jako funkcje strzałek w klasie Angular (3 odpowiedzi) Arrow vs klasyczna metoda w klasie ES6 (1 ODPOWIEDŹ) Zamknięty 2 lata temu .
class App extends Component {
  constructor(props) {
    ...
  }

  onChange = (e) => this.setState({term: e.target.value})

  onSubmit(e){
    e.preventDefault();
    const api_key = "C1hha1quJAQZf2JUlK";
    const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
  }

  render() {
    return (
      <div>
        <form onSubmit={this.onSubmit}>
          <input value={this.state.term} onChange={this.onChange}/>
          <button>Search!</button>
        </form>
      </div>
    );
  }
}

Jaka jest różnica pomiędzy dwoma typami funkcji zadeklarowanymi w klasie (onChange i onSubmit). Dostaję błąd w odniesieniu do tego.sate in const url jeśli I deklaruje ją jako metodę klasy ES6, ale zmiana jej na funkcję arrow ją naprawia.

Chcę wiedzieć, jak dokładnie " to " jest obsługiwane w obu przypadkach

Również, jak zrobić to w drugą stronę? Powiedzmy, że jeśli chcę użyć tej samej funkcji onSubmit (metoda klasy ES6), ale chcę obsłużyć to, gdy ją wywołam (w elemencie formularza), Jak to zrobić ?

używając tego.onSubmit.bind (this)?

Author: d_bhatnagar, 2018-02-22

5 answers

Ważne jest, aby wiedzieć, że składnia ta:

class A {
  method = () => {}
}

Jest tylko cukrem składniowym do tworzenia metody instancji w konstruktorze klasy:

class A {
  constructor() {
    this.method = () => {}
  }
}

Uwaga: Ta składnia nie jest jeszcze oficjalną częścią języka JavaScript (obecnie w etapie 3), więc musisz użyć transpilera podobnego do Babel do obsługi .

Wartość this wewnątrz method jest klasą A, ponieważ na to wskazuje this w konstruktorze (od strzałka funkcje dziedziczą kontekst z zakresu, w którym są zdefiniowane):

class A {
  constructor() {
    this.method = () => this;
  }
}

const instance = new A();
console.log(instance.method() === instance); // true

Definiowanie zwykłej (Nie-funkcji strzałkowej) metody na klasie tworzy metodę na prototypie klasy (nie instancję), ale nie ustala reguł co this będzie (ponieważ this jest dynamiczna w JS i zależy od tego, jak funkcja jest wywoływana, a nie jak jest zdefiniowana ).

class A {
  method() {}
}

console.log(new A().method === A.prototype.method); // true

Jeśli metody zdefiniowane w którymkolwiek z tych sposobów są wywoływane na instancji klasy (poprzez .), zgodnie z regułą jak this jest związana, gdy funkcja jest wywoływana jako metoda obiektu, this wskaże instancję klasy w obu przypadkach:

class A {
  constructor() {
    this.methodOnInstance = () => this;
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype() === instance // true
);

Jedną z głównych różnic między dwiema powyższymi deklaracjami metody jest to, że metoda instancji ma this zawsze stałe do instancji klasy, podczas gdy metoda class (prototype) nie (możemy ją zmienić za pomocą funkcji .prototyp.zastosuj lub funkcja.prototyp.call )

class A {
  constructor() {
    this.methodOnInstance = () => this;
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype.call('new this') === 'new this' // true
);

Częstym zjawiskiem, w którym this zmiany znajdują się wewnątrz procedury obsługi zdarzeń, gdzie procedura obsługi zdarzeń wywołuje przekazaną do niej funkcję i wiąże kontekst z elementem, na którym zdarzenie miało miejsce (tak więc nadpisuje wartość this jako element, który został kliknięty lub cokolwiek to było zdarzenie)

Dzieje się tak również w Reaccie dla wszystkich (syntetycznych) procedur obsługi zdarzeń DOM.

Dlatego, jeśli aby kontekst naszej metody zawsze wskazywał na instancję komponentu Reactowego, możemy użyć tej metody.

Innym sposobem ograniczenia kontekstu, ale bez użycia specjalnej składni metody instancji, która wymaga Babel, jest bezpośrednie utworzenie metody instancji przez utworzenie nowej funkcji z metody klasy (prototype) z powiązanym kontekstem (za pomocą funkcji .prototyp.bind):

class A {
  constructor() {
    this.methodOnInstance = this.methodOnPrototype.bind(this);
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype() === instance // true
);

To pozwala nam dotrzeć do tego samego wynik jako użycie składni metody wystąpienia specjalnego, ale z aktualnie dostępnymi narzędziami (ES2017 i under).

Jeśli z jakiegoś powodu chcemy metody, która jest zawsze związana z czymś, co nie jest instancją klasy, możemy to zrobić również: {21]}

class A {
  constructor() {
    this.method = this.method.bind(console);
  }
  method() { return this; }
}

const instance = new A();
console.log(
  instance.method() === console // true
);
 17
Author: nem035,
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-02-27 03:11:53

Wyrażenie funkcji strzałki ma krótszą składnię niż funkcja ekspresji i nie ma własnego tego, argumentów, super, czy nowy.cel. Te wyrażenia funkcyjne najlepiej nadają się dla NIE-metody funkcji i nie mogą być używane jako konstruktory.

Funkcje strzałek leksykalnie wiążą swój kontekst, więc w rzeczywistości odnosi się to do kontekstu początkowego.

W deklaracji funkcji ES3/4 można użyć this przechowując ją w innej zmiennej.

const that = this;
onSubmit(e){
    e.preventDefault();
    const api_key = "***************";
    const url = `http://api.giphy.com/v1/gifs/search?q=${that.state.term}&api_key=${api_key}`;
  }
 1
Author: void,
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
2018-02-22 05:25:34
Jak mam to zrobić w drugą stronę? Powiedzmy, że jeśli chcę użyć tej samej funkcji onSubmit (metoda klasy ES6), ale chcę obsłużyć to, gdy ją wywołam (w elemencie formularza), Jak to zrobić ?

Używając tego.onSubmit.bind (to)?

Tak musisz powiązać metodę z komponentem w konstruktorze. Dzieje się tak dlatego, że funkcje strzałek są automatycznie przypisywane do klasy, dlatego zakres tego jest ustawiany w metodzie. While {[0] } Jest funkcją regularną, która nie jest jeszcze związana dlatego to wewnątrz metody będzie odwoływać się do funkcji, a nie do komponentu.

 0
Author: Adarsh,
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

Musisz użyć bind w konstruktorze swojej klasy z metodą klasy ES6. Zasadniczo funkcje strzałek robią to za ciebie automatycznie.

constructor(props) {
  super(props);

  this.onSubmit = this.onSubmit.bind(this);
}

Ważniejsze jest to, że wierzę, że funkcja arrow tutaj zostanie utworzona na każdej instancji klasy, gdzie metoda klasy ES6 będzie częścią prototypu klasy i udostępniona wszystkim instancjom.

 0
Author: John Halbert,
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
2018-02-22 05:28:01

Zasadnicza różnica polega na tym, że w ES5 nie mamy automatycznego wiązania, co oznacza, że musisz ręcznie powiązać funkcję obsługi zdarzeń, aby grać z state lub props wewnątrz funkcji w reaccie. Ale w ES6 robi automatyczne wiązanie. To jest kluczowa różnica

ES5: musisz bindować onSubmit najlepiej w konstruktorze

//is valid
this.onSubmit = this.onSubmit.bind(this);

onSubmit(e){
    e.preventDefault();
    const api_key = "C1hha1quJAQZf2JUlK";
    const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
  }

ES6:

Poniższy tekst jest ważny, ponieważ powoduje automatyczne wiązanie.

onChange = (e) => this.setState({term: e.target.value})
 0
Author: Hemadri Dasari,
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
2018-02-22 05:42:29