Definiując funkcję w języku Javascript możemy też tworzyć klasy obiektów, a dokładniej konstruktory tych klas. Tutaj należy zwrócić szczególną uwagę na zmienną "this" wskazującą na aktualny obiekt klasy, bo zasięg tej zmiennej może być ograniczony lokalną zmienną "this" zwykłej funkcji której definicja znajduje się wewnątrz konstruktora. Problemu tego nie ma z funkcjami strzałkowymi które nie tworzą swoje lokalnego kontekstu (closure) i dlatego zawsze odwołują się do "this" widzianego na zewnątrz, jest to szczególnie użyteczne w momencie kiedy użyjemy całego łańcucha funkcji ze strzałką gdzie wynik jednej funkcji => jest parametrem wejściowym drugiej funkcji strzałkowej.
function BookList (prefix) {
this.prefix = prefix;
this.prefix2 = 'd'
this.makeGetBooksWithPrefix = function() {
return () => {
/* zmienna "this" objektu klasy BookList lub*/
/* zmienna "this" metody getBooksWithPrefix */
return ["book1", "book2", "book3"].map(book => `${this.prefix}${book}` );
}
}
this.getBooksWithPrefix1 = (() => {
return () => {
/* atrybut "this.prefix" objektu klasy BookList, nieokreślony jeszcze w definicji klasy */
return ["book1", "book2", "book3"].map(book => `${this.prefix}${book}` );
}
})();
this.getBooksWithPrefix2 = (() => {
return () => {
/* atrybut "this.prefix2" klasy BookList, określony w definicji klasy */
return ["book1", "book2", "book3"].map(book => `${this.prefix2}${book}` );
}
})();
this.getBooksWithPrefix3 = (function() {
/* funkcja tworzy nowy lokalny "this", war. this.prefix2 będzie undefined */
return () => {
/* zmienna "this" metody getBooksWithPrefix3 */
return ["book1", "book2", "book3"].map(book => `${this.prefix2}${book}` );
}
})();
this.getBooksWithPrefix4 = (function() {
/* lokalne "this" zostaje zastąpione kontekstem objektu BookList dzięki bind(this)*/
return () => {
/* zmienna "this" metody getBooksWithPrefix3 */
return ["book1", "book2", "book3"].map(book => `${this.prefix2}${book}` );
}
}).bind(this)();
}
let c = new BookList('*');
let d = new BookList('x');
/* użycie funkcji wygenerowanej lokalnie w miejscu wywołania: */
console.log( c.makeGetBooksWithPrefix()() );
console.log( d.makeGetBooksWithPrefix()() );
/* użycie funkcji wygenerowanych wcześniej w konstruktorze: */
console.log( d.getBooksWithPrefix1() );
console.log( d.getBooksWithPrefix2() );
console.log( d.getBooksWithPrefix3() );
console.log( d.getBooksWithPrefix4() );
// wynik funkcji stworzonej lokalnie:
// [ '*book1', '*book2', '*book3' ]
// [ 'xbook1', 'xbook2', 'xbook3' ]
// wynik funkcji stworzonych w konstruktorze:
// [ 'xbook1', 'xbook2', 'xbook3' ]
// [ 'dbook1', 'dbook2', 'dbook3' ]
// [ 'undefinedbook1', 'undefinedbook2', 'undefinedbook3' ]
// [ 'dbook1', 'dbook2', 'dbook3' ]
Przykład powyżej pokazuje jak zastosowanie notacji strzałkowej (arrow functions) zmienia znaczenie zmiennej "this". Każde odwołanie do "this" wewnątrz funkcji strzałkowej odnosi się do zasięgu w którym taka funkcja jest definiowana, jeżeli brakuje szukanej zmiennej to sprawdzany jest zasięg bardziej zewnęczny - w przykładzie powyżej this.prefix
nie jest zdefiniowany w funkcji makeGetBooksWithPrefix
więc pobrany jest prefix z funkcji BookList
. Ponieważ funkcja makeGetBooksWithPrefix
tworzy i zwraca właściwą funkcję anonimową w miejscu jej wywołania to właśnie w tym momencie określana jest wartość this.prefix
. (jest to aktualna wartość atrybutu prefix w obiekcie klasy BookList
).
Podobnie zachowuje się anonimowa funkcja przypisana do zmiennej getBooksWithPrefix1
- wartość this.prefix
jest nieokreślona w momencie generowania tej funkcji więc użycie tej funkcji dla konkretnego obiektu pobiera aktualną wartość this.prefix
tego obiektu.
Funkcja przypisana do atrybutu getBooksWithPrefix2
jest dokładnie taką samą anonimową funkcją strzałkową wygenerowaną przez inną anonimową funkcję strzałkową jak getBooksWithPrefix1
ale różnica polega na tym że funkcja ta odwołuje się do atrybutu this.prefix2
który jest dostępny w definicji konstruktora.
Następny przypadek to zwykła funkcja która zwraca funkcję strzałkową i przypisuje ją do atrybutu getBooksWithPrefix3
. Tutaj zwracana funkcja strzałkowa nie ma dostępu ani do this.prefix
ani też do this.prefix2
więc zwrócona będzie wartość "undefined" (zwykła funkcja zdefiniowana za pomocą słowa kluczowego function
tworzy swoją lokalną zmienną this).
I ostatnia funkcja przypisana do pola getBooksWithPrefix4
to dokładna kopia funkcji z pola getBooksWithPrefix3
, jedyna różnica to użycie bind(this)
na funkcji anonimowej function() {...
bezpośrednio przed jej wywołaniem, funkcja bind(this)
przekazuje do funkcji anonimowej kontekst objektu klasy, więc aktualne wartości pól objektu klasy BookList
są ponownie dostępne.