Metody w obiektach ES6: użycie funkcji strzałkowych


97

W ES6 oba są legalne:

var chopper = {
    owner: 'Zed',
    getOwner: function() { return this.owner; }
};

i jako skrót:

var chopper = {
    owner: 'Zed',
    getOwner() { return this.owner; }
}

Czy można również korzystać z nowych funkcji strzałek? Próbując czegoś takiego

var chopper = {
    owner: 'John',
    getOwner: () => { return this.owner; }
};

lub

var chopper = {
    owner: 'John',
    getOwner: () => (this.owner)
};

Otrzymuję komunikaty o błędach sugerujące, że metoda nie ma dostępu this. Czy to tylko kwestia składni, czy nie możesz używać metod grubych potoków wewnątrz obiektów ES6?


11
Jednym z największych punktów nowej składni funkcji było to, że traktuje ona thisinaczej. Jest definiowana przez środowisko leksykalne, w którym została utworzona funkcja, co oznacza, że thiswartość, w której utworzysz chopperzmienną, będzie thiswartością funkcji. Innymi słowy, nie będzie odnosić się do chopperobiektu.

1
Używając składni grubej strzałki? Tylko jeśli zmienisz thiswartość, najpierw tworząc chopperobiekt, a następnie wykonując przypisanie w funkcji, która thiswskazuje na ten obiekt. Można to całkiem łatwo osiągnąć za pomocą funkcji konstruktora.

1
To demo będzie działać w przeglądarce Firefox. Chrome jeszcze tego nie ma. jsfiddle.net/bfyarxfe

2
@fox, musisz użyć „use strict” na tym jsfiddle.
Walter Chapilliquen - wZVanG

1
@fox: Działa dobrze w obsługiwanym środowisku. Firefox nie ma jeszcze pełnej obsługi. Wypróbuj w Continuum i console.log()wynik wywołania metody. To działa.

Odpowiedzi:


158

Funkcje strzałkowe nie są przeznaczone do użytku w każdej sytuacji, a jedynie jako krótsza wersja staromodnych funkcji. Nie mają na celu zastąpienia składni funkcji za pomocą functionsłowa kluczowego. Najczęstszym przypadkiem użycia funkcji strzałkowych są krótkie „lambdy”, które nie zmieniają definicji this, często używane podczas przekazywania funkcji jako wywołania zwrotnego do jakiejś funkcji.

Funkcji strzałkowych nie można używać do pisania metod obiektowych, ponieważ, jak już zauważyłeś, ponieważ funkcje strzałkowe zamykają się nad thiskontekstem obejmującym leksykalnie, thiswewnątrz strzałki jest to, które było aktualne w miejscu zdefiniowania obiektu. To znaczy:

// Whatever `this` is here...
var chopper = {
    owner: 'Zed',
    getOwner: () => {
        return this.owner;    // ...is what `this` is here.
    }
};

W twoim przypadku chcąc napisać metodę na obiekcie, powinieneś po prostu użyć tradycyjnej functionskładni lub składni metody wprowadzonej w ES6:

var chopper = {
    owner: 'Zed',
    getOwner: function() {
        return this.owner;
    }
};

// or

var chopper = {
    owner: 'Zed',
    getOwner() {
        return this.owner;
    }
};

(Są między nimi niewielkie różnice, ale są one ważne tylko wtedy, gdy używasz programu superw programie getOwner, którego nie jesteś, lub kopiujesz getOwnerdo innego obiektu).

Na liście mailingowej es6 odbyła się debata na temat zmiany w funkcjach strzałek, które mają podobną składnię, ale mają własną this. Jednak ta propozycja została źle przyjęta, ponieważ jest to zwykły cukier składniowy, pozwalający ludziom zaoszczędzić na wpisywaniu kilku znaków i nie zapewnia nowej funkcjonalności w stosunku do istniejącej składni funkcji. Zobacz temat niezwiązane funkcje strzałek .


Jeśli dobrze to czytam, wydaje się, że sugeruje to, że lista mailingowa pozbawia priorytety cukru syntaktycznego, nawet jeśli prowadziłoby to do większej jednolitości / czytelności kodu. W obecnym stanie znacznie trudniej jest używać funkcji grubych strzałek w kontekście OOP pod ES6 niż, powiedzmy, pod coffeescript.
lis

Jak rozumiem, cukier syntaktyczny jest uważany za ważny powód do rozważania rozszerzeń językowych, ale jak mówisz z niższym priorytetem - innymi słowy, poprzeczka jest wyższa w przypadku takich propozycji.

13

W tej linii getOwner: => (this.owner)powinno być:

var chopper = {
    owner: 'John',
    getOwner: () => this.owner
}; //here `this` refers to `window` object.

Musiałbyś zadeklarować thisw funkcji:

var chopper = {
    owner: 'John',
    getOwner() { return this.owner }
};

Lub:

var chopperFn = function(){

    this.setOwner = (name) => this.owner = name;
    Object.assign(this,{
        owner: 'Jhon',
        getOwner: () => this.owner,
    })

}

var chopper = new chopperFn();
console.log(chopper.getOwner());
chopper.setOwner('Spiderman');
console.log(chopper.getOwner());


1
Tutaj pojawia się błąd:"TypeError: Cannot read property 'owner' of undefined\n at Object.chopper.getOwner
lis

Widzę, że jest to prawidłowe użycie, jednak metoda esta zawsze zwraca obiekt okna. Musiałbyś zadeklarować thisw funkcji.
Walter Chapilliquen - wZVanG

2
thisniekoniecznie odnosi się do window. Odnosi się do jakiejkolwiek bieżącej wartości thisw otaczającym środowisku, co może, ale nie musi window. Może to miałeś na myśli. Chcę się tylko upewnić, że rozumie, że to nie jest jakaś domyślna wartość.

@torazaburo To dla mnie w porządku, próbowałem, thisteraz odnosi się do klasy
Walter Chapilliquen - wZVanG

2
To, co napisałeś, jest równoważne, ale bardziej szczegółowe niż zwykłe pisanie var chopperFn = function() { this.owner = 'Jhon'; this.getOwner = () => this.owner; }.

1

Szybka wskazówka, której używam, aby używać funkcji strzałek.

  • Użyj funkcji innych niż strzałki dla metod, które będą używane object.method() składni. (Są to funkcje, które otrzymają znaczącą thiswartość od wywołującego).
  • Użyj funkcji strzałek do prawie wszystkiego innego.

1

Inna wskazówka, w trybie ścisłym, thisnadal odnosi się do Window zamiast undefined.

  (() => {
    "use strict";
    console.log(this); // window
  })();

  (function () {
    "use strict";
    console.log(this); // undefined
  })();


0

Jeśli musisz użyć funkcji strzałek, możesz zmienić thisna chopper,

var chopper = {
  owner: "John",
  getOwner: () => chopper.owner
};

Chociaż nie jest to najlepsza praktyka, po zmianie nazwy obiektu należy zmienić tę funkcję strzałki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.