webdevlpr

Jednostavno receno, prototipsko nasljedjivanje se odnosi na mogucnost pristupa svojstvima jednog objekta iz drugog objekta, sto umanjuje potrebu dupliciranja koda. Klase su implementirane na osnovu prototipa i ovdje pricamo vise o tome sta se desava u pozadini.

Svaki objekat ima privatno svojstvo [[Prototype]] koje za vrijednost ima ili referencu na drugi objekat ili null. U primjeru ispod munchkin objekat za prototip dobija cat objekat.

let cat = {
says: 'meow',
talk() {
console.log(`${this.name} says ${this.says}!`);
// this je uvijek objekat prije tacke _____.svojstvo
}
};

let munchkin = {
name: 'Odie',
breed: 'Munchkin',
__proto__: cat
};

munchkin.talk(); // Odie says meow!

munchkin.talk() metoda ne postoji u munchkin objektu, ali kako je njegov prototip cat objekat, to je sledece mjesto gdje ce JavaScript engine nastaviti potragu. Potom bi je trazio u prototipu cat objekta, taj objekat potom ima svoj [[Prototype]], sve dok trazena metoda ne bude pronadjena ili dok pretraga ne dosegne kraj lanca, odnosno vrijednost null koja nema prototip i tu pretraga zavrsava sa greskom.

[[Prototype]] nije samo apstraktni koncept i da bi ga vidjeli mozemo napisati console.log(munchkin) i pregledati rezultat u DevTools konzoli.

×  Object
     breed: "Munchkin"
     name: "Odie"
  ×  [[Prototype]]: Object
        says: "meow"
      > talk: ƒ talk()
      × [[Prototype]]: Object
          > constructor: ƒ Object()
          > hasOwnProperty: ƒ hasOwnProperty()
            ... 

Istom prototipu je moguce pristupiti direktno:

console.log(munchkin.__proto__); // cat
console.log(munchkin.__proto__.__proto__); // Object.prototype
// Vise o njemu kasnije
console.log(munchkin.__proto__.__proto__.__proto__); // null
// Dosegli smo kraj lanca nasljedjivanja za ovaj objekat

[[Prototype]] referenca ne moze ici u krug.

TypeError:Cyclic__proto__valuepredatormunchkincat
let predator = {};
let cat = { __proto__: predator };
let munchkin = { __proto__: cat };

predator.__proto__ = munchkin; // TypeError: Cyclic __proto__ value

for..in petlje su svjesne naslijedjenih svojstava sto znaci da ce se data akcija ponoviti i za nasljedjena svojstva (nije slucaj sa klasama). Vidljive su petljama jer deskriptor enumerable ovih svojstava nije podesen da bude false. Deskriptore je moguce podesiti rucno.

let predator = { dangerous: 'very' };
let cat = { says: 'meow', __proto__: predator };
let munchkin = { name: 'Odie', __proto__: cat };

for (let prop in munchkin) {
console.log(prop); // name, says, dangerous
}

Postoji nacin da testiramo da li je svojstvo dio objekta ili ne sa obj.hasOwnProperty(key) — vraca true ili false.

for (let key in munchkin) {
if (munchkin.hasOwnProperty(key)) {
console.log(key); // name
} else {
console.log(key); // says, dangerous
}
}

Ili mozemo objekat pretvoriti u niz. On nece uzeti u obzir nasljedjena svojstva. Za nizove je prikladnije koristiti for..of petlju:

let munchkinArray = Object.keys(munchkin); // ['name']
for (let key of munchkinArray) {
console.log(key); // name
}

Definisanje prototipa

U primjerima iznad je koristeno svojstvo __proto__. On je (getter i setter) svojstvo za pristupanje prototipu objekta. Smatra se zastarjelim, ali ga je prihvatljivo koristiti za vrijeme kreiranje objekta {__proto__: ...}. Preporuceni nacin za dodjeljivanje prototipa za vrijeme kreiranje objekta je Object.create(prototype, propertiesObject) (ili koristenjem klase). Prvi parametar je objekat koji ce novi objekat naslijediti, a kroz drugi opcioni parametar propertiesObject mozemo dodavati svojstva i podesiti njihove deskriptore.

let munchkin = Object.create(cat, { 
'name': {
value: 'Odie',
enumerable: true, // prikazuje se u petljama
writable: true, // promjenjiva vrijednost
configurable: true // deskriptori se mogu modifikovati, a svojstvo brisati
},
'breed': {
value: 'Munchkin',
enumerable: true
// nenavedeni deskriptori imaju vrijednost false
}
});

Sada necemo definisati svojstva kroz drugi parametar u Object.create(). Ukoliko u sklopu njega ne navedemo neki deksriptor, njegova vrijednost ce biti false. Ako svi trebaju imati vrijednost true navodjenje svakog deskriptora je suvisno. Smislenije je dodati svojstva nakon kreiranja objekta:

let munchkin = Object.create(cat);
munchkin.name = 'Odie';

// ili __proto__ *za vrijeme kreiranje objekta*
let korat = { __proto__: cat, name: Whiskers, breed: 'korat' };

Za mijenjanje prototipa postojecem objektu koristimo Object.setPrototypeOf(obj, proto) metodu:

let predator = { dangerous: 'very' };
let cat = { says: 'meow' };
let munchkin = { name: 'Odie' };

cat.__proto__ = predator; // zastarjelo
Object.setPrototypeOf(munchkin, cat);

console.log(munchkin.dangerous); // very

Medjutim, dinamicno dodjeljivanje prototipa treba izbjegavati. Vecina interpretera JavaScript koda je optimizovalo mehanizam prototipnog nasljedjivanja. Ddefinisanje prototipa objekta nakon njegovog kreiranja ugrozava ovu optimizaciju. Ukoliko performans i brzina izvrsavanja koda nije vazna, onda ovo nije problem (ali onda prototip gubi svrhu). U suprotnom, dinamicno definisanje prototipa treba izbjegavati ako je moguce dodijeliti prototip za vrijeme kreiranja objekta.

Za dobijanje prototipa nekog objekta umjesto __proto__ svojstva tu treba koristiti Object.getPrototypeOf(obj) metoda.

let cat = { says: 'meow' };
let munchkin = Object.create(cat);

// munchkin.__proto__; // zastarjelo
Object.getPrototypeOf(munchkin); // cat

Jos jedan nacin za definisanje prototipa objekta je kroz konstruktor..

Funkcija.prototype svojstvo

Za razumijevanje ove teme je, izmedju ostalog, neophodno poznavanje konstruktora i operatora new. Ukratko, konstruktor je funkcija koja inicijalizuje objekat. Poziva se sa kljucnom rijeci new i po konvenciji se imenuje sa prvim velikim slovom. Funkcija za rezultat vraca objekat i omogucava kreiranje vise slicnih objekata.

function Cat(name, breed) {
this.name = name;
this.breed = breed;
}

let odie = new Cat('Odie', 'Munchkin');
let whiskers = new Cat('Whiskers', 'Korat');

console.log(odie); // Cat {name: 'Odie', breed: 'Munchkin'}
console.log(whiskers.breed); // Korat

prototype svojstvo

Funkcije su objekti. A objekti imaju svojstva (key-value parove). Uz to funkcije su specificne po tome sto imaju predefinisano fn.prototype svojstvo. Ovdje treba napraviti razliku izmedju .prototype i [[Prototype]] objekta. [[Prototype]] je prototip koji funkcija (ili bilo koji drugi objekat nasledjuje), fn.prototype je predefinisano svojstvo svih funkcija i sada pokusavamo shvatiti njegovu funkciju.

function funkcijaJeObj() {}

console.dir(funkcijaJeObj);

Umjesto console.log() je koristen console.dir() jer log prikazuje toString reprezentaciju funkcije (njeno tijelo u string obliku koje se moze pozvati dodavanjem zagrada), dok dir prikazuje interaktivnu listu svojstava JavaScript objekta.

Rezultat u konzoli:

×  ƒ funkcijaJeObj()
      arguments: null
      caller: null
      length: 0
      name: "funkcijaJeObj"
    × prototype: 
         > constructor: ƒ funkcijaJeObj()
         > [[Prototype]]: Object
      [[FunctionLocation]]: app.js:1
    > [[Prototype]]: ƒ ()
    > [[Scopes]]: Scopes[1]

Iako nismo sami dodali .prototype svojstvo funkciji, ono je tu i vec sadrzi objekat sa nekim svojstvima: {constructor: ƒ, [[Prototype]]: Object}.
Mozemo dodavati i modifikovati svojstva .prototype-a, ali ono ima efekat samo kada se pozove funkcija sa kljucnom rijeci new. Zasto? Jer se konstruktor funkcija poziva sa kljucnom rijeci new da bi kreirala novi objekat i njeno prototype svojstvo u procesu kreiranja postaje referenca [[Prototype]] objekta koji je kreirala.
constructor() metoda uvijek pokazuje na samu funkciju sto ce se vidjeti u sledecem primjeru..

Kreiracemo praznu konstruktor funkciju i dodati metodu u njen .prototype objekat. Ako pozovemo funkciju, ona ce nam vratiti prazan objekat, ali ce objekat imati pristup metodi koja je dodana .prototype-u funkcije iz koje je nastao:

// Kreiranje prazne konstruktor fn
function Funkcija() {}

// Dodavanje metode u njeno .protoype svojstvo
Funkcija.prototype.svojstvo = function() {
console.log("Zdravo iz prototipa!");
};

let obj1 = new Funkcija();
// Jer obj1 ima referencu na .prototype za svoj [[Prototype]]
// Je isto kao da smo napisali:
// obj1.__proto__.svojstvo = function() {...}

obj1.svojstvo(); // Zdravo iz prototipa!

console.log(Funkcija.prototype.constructor); // Funkcija() {}
console.log(obj1.constructor === Funkcija); // true

U konzoli:

× Funkcija {}
   × [[Prototype]]: Object
      > svojstvo: ƒ ()
      > constructor: ƒ Funkcija()
      > [[Prototype]]: Object

Ovaj odnos prototype svojstva konstruktora i [[Prototype]] svojstva objekta je mozda vizuelno lakse razumjeti:

Funkcijaobjekat.prototypenew Funkcija()[[Prototype]][[Prototype]]: Object__proto__svojstvo: ƒ svojstvo()constructor : ƒ Funkcija(){}

Predefinisani prototipi

  1. Rekli smo da sve funkcije imaju prototype svojstvo. Medjutim, ono sluzi samo funkcijama koje se izvrsavaju sa kljucnom rijeci new za definisanje prototipa [[Prototype]] objekta koji ce new inicijalizovati.

  2. Sa druge strane, JavaScript dopusta kreiranje raznih objekata koristeci new, kao let arr = new Array(), let date = new Date(), let obj = new Object(), let fn = new Function(), let map = new Map(), let str = new String() itd. Mozemo zakljuciti da svaki put kada kreiramo objekat za to koristimo konstruktor. Cak i njihova imena po konvenciji pocinju velikim slovom.

  3. Ovi predefinisani konstruktori u prototype svojstvu imaju predefinisane metode i svojstva koje se mogu koristiti na novo kreiranom objektu jer ih je objekat naslijedio. U konzoli cemo ispisati sadrzaj prototype svojstva jednog od konstruktora da bi vidjeli kako izgleda.
console.log(Array.prototype); 
// predefinisane metode za manipulisanje nizova

at: ƒ at()
concat: ƒ concat()
// ...
sort: ƒ sort()
splice: ƒ splice()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
unshift: ƒ unshift()
values: ƒ values()
Symbol(Symbol.iterator): ƒ values()
[[Prototype]]: Object

Ovo su sve one vec vrlo poznate metode za nizove. Kreiranjem objekta sa new Array() (ili skraceno []), novoinicijalizovani niz dobija Array.prototype za svoj [[Prototype]].

let arr = new Array(); // isto kao let arr = []
console.log(arr.__proto__ === Array.prototype); // true
Arrayarr.prototypenew Array()[[Prototype]][[Prototype]]: Object__proto__at: ƒ at()concat: ƒ concat(){}

Ta svojstva su sada dostupna arr objektu jer se nalaze u njegovom prototipskom lancu. Primjer metode koju nismo kreirali, ali je JavaScript engine pronasao u [[Prototype]] i primjenio na novom objektu:

let arr = new Array(1, 2, 3, 4);  
console.log(arr.at(-1)); // 4

Ispod cemo vidjeti kako JavaScript engine reaguje kada ne moze pronaci metodu u samom objektu, niti u prototipnom lancu objekta. Objekat u ovom slucaju kreiram sa Object konstruktorom jer on u Object.prototype nema metodu za nizove.

let obj = new Object({1: 1, 2: 2, 3: 3, 4: 4});
obj.at(2); // obj.at is not a function

Ako se vratimo na sliku, strelice od objekta do prototype svojstva su dvosmjerne jer se ne radi o kopiji vec [[Prototype]] ima referencu na prototype konstruktora.

let arr = [1, 2, 3];

arr.__proto__.num = 3;
Array.prototype.num; // 3
console.log(arr.__proto__ === Array.prototype); // true

Objekat ne cuva metode prototipa. Ono sto on cuva su samo podaci poput stavki niza [1, 2, 3].

Lanac predefinisanih prototipa

Mozda ste primjetili da Array.prototype objekat na kraju predefinisanih metoda i svojstava ima naveden i [[Prototype]]: Object. To je zato sto svi oblici ugradjenih prototipa nasljedjuju prototip obicnog objekta i na ovaj nacin je on poslednji u prototipskom lancu nasljedjivanja.

let arr = [];
console.log(arr.__proto__); // Array.prototype
console.log(arr.__proto__.__proto__); // Object.prototype
console.log(arr.__proto__.__proto__.__proto__); // null

// ili

console.log(Array.prototype.__proto__); // Object.prototype
console.log(Array.prototype.__proto__.__proto__); // null

U ovom slucaju bi JavaScript engine prvo trazio metodu ili svojstvo u samom objektu, potom u Array.prototype, pa u Object.prototype i nakon toga dobijamo gresku ukoliko ga ne nadje negdje u lancu.

Sta se nalazi u Array.__proto__?
Array je konstruktor, a konstruktor je funkcija. Sve funkcije (zajedno sa konstruktorima) za svoj [[Prototype]] imaju Function.prototype.

Array.__proto__ === Function.prototype; // true

Funkcija je objekat i ona ima referencu na Object.prototype.

Array.__proto__.__proto__ === Object.prototype; // true
Object.prototypenullodgovarajuci Konstruktor.prototypeƒ fn(){}[]‘string’

Sada kada znamo kako pristupiti globalnim prototipima, napomenucu da treba izbjegavati mijenjanje izvornih prototipa da bi izbjegli konflikte usljed imenovanja. Medjutim, modifikacija metoda prototipa moze biti korisna za polifilovanje (kreiranje zamjenske metode koja postoji u JavaScript specifikaciji u pretrazivacu koji je jos nije implementirao).

if (!Array.prototype.join) {
Array.prototype.join = function() {...}
}

Kreiranje naseg prototipskog nasljedjivanja

Recimo da imamo konstruktor Oblik, ali ga zelimo prosiriti i iz njega izvesti nekoliko novih konstruktora raznih oblika:

function Oblik() {}
Oblik.prototype.oboji = function() {};

function Kocka() {}
Kocka.prototype = Object.create(Oblik.prototype);
// Sada je property svojstvo Kocka = Oblik.prototype
// i oboji() metoda ce biti dostupna svim objektima Kocke

Kocka.prototype.izracunajDimenzije = function() {}

let kocka = new Kocka();

Medjutim postoje ne tako ceste situacije kada zelimo novi objekat kreirati dinamicno, kada nam tip objekta nije unaprijed poznat ili zelimo kreirati objekat nekog tipa koji ce biti odredjen za vrijeme izvrsavanja koda. Tada new Kocka() nije opcija. constructor svojstvo u prototipu nam omogucuje da kreiramo novi objekat tako sto cemo koristiti postojeci objekat: new kocka.constructor().

Ali postoji mali problem ako dopisemo sledece

// ...
let kocka = new Kocka();
let kockica = new kocka.constructor();

kockica ne nasljedjuje Kocku, vec Oblik. Zasto?
Stvar je u tome kako smo izvrsili nasljedjivanje.
Kocka.prototype = Object.create(Oblik.prototype) linija koda je potpuno zamjenila sva prethodna svojstva koja su zivjela u prototype-u Kocke, a predefinisani su bili constructor i [[Prototype]]. Prvo constructor svojstvo u lancu ce biti ono od konstruktora Oblik i na njemu ce kljucna rijec new kreirati novi objekat. Ispod je vrijednost kocka objekta u konzoli console.log(kocka):

×  Kocka {}
    × [[Prototype]]: Oblik
       ~ nedostaje: constructor: ƒ Kocka()~
       > izracunajDimenzije: ƒ ()
       × [[Prototype]]: Object
          > oboji: ƒ ()
          > constructor: ƒ Oblik() 
          > [[Prototype]]: Object

Zato je dobra praksa resetovati konstruktor svojstvo nakon nasljedjivanja druge konstruktor funkcije, ovako:

Kocka.prototype = Object.create(Oblik.prototype);
// Ispod resetujemo konstruktor i dodajemo metode
// koje pripadaju Kocka prototipu
Kocka.prototype.constructor = Kocka;
Kocka.prototype.izracunajDimenzije = function() {}

Sada ce pozivanje new kocka.constructor() kreirati objekat konstruktorom Kocka.

Mozemo napisati funkciju koja ce nas spasiti ponavljanja istih linija koda kada god zelimo prosiriti neki konstruktor:

function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}

extend(Kocka, Oblik);

Pozivanje roditeljskog konstruktora

S obzirom da na objekat uticu nasljedjeni prototipi, trebalo bi da naslijedi i clanove, ali se to u ovom slucaju ne desava automatski. Pozvacemo roditeljsku funkciju sa Oblik.call(this, argument) da bi bila svjesna objekta na kom treba dodati clanove.

function Oblik(boja) {
this.boja = boja;
}

function Kocka(stranicaA, boja) {
Oblik.call(this, boja);
this.stranicaA = stranicaA;
}

Kocka.prototype = Object.create(Oblik.prototype);
Kocka.prototype.constructor = Kocka;

let kocka = new Kocka(50, 'crvena');
// kocka = { stranicaA: 50, boja: crvena }

.call() metoda poziva funkciju sa datom this vrijednosti i argumentima. Proslijedili smo joj novi objekat kao this. Da smo pozvali funkciju sa Oblik(boja), this bi u funkciji pokazivao na globalni objekat (window u pretrazivacu), sto znaci da bi svojstvo boje bilo dodjeljeno globalnom objektu: window.boja = 'crvena'.

Sintaksa: fn.call(thisObj, arg, /*...,*/, argN).

Ali, ako ne zelimo dodavati clanove nekih klasa direktno u objekat, vec u prototip, tada prototipu mozemo dodjeliti novu instancu Oblik konstruktor Kocka.prototype = new Oblik();

function Oblik() {
this.boja = 'crna';
}

Oblik.prototype.nacrtaj = function() {
console.log(this.boja + ' ' + this.constructor.name);
}

function Kocka(stranicaA) {
this.stranicaA = stranicaA;
}

Kocka.prototype = new Oblik(); // ***
Kocka.prototype.constructor = Kocka;

let kocka = new Kocka(50);
kocka.nacrtaj(); // crna kocka

U konzoli kocka izgleda ovako:

×  Kocka {}
      stranicaA: 50
    × [[Prototype]]: Oblik
         boja: "crna"
       > constructor: ƒ Kocka(stranicaA)
       × [[Prototype]]: Object
          > nacrtaj: ƒ ()
          > constructor: ƒ Oblik() 
          > [[Prototype]]: Object

Rekreiranje new operatora

Da bi bolje razumjeli kako new radi, pravicemo se da ne postoji i rekreirati njegove korake. Pravimo funkciju koja:

  1. kreira prazan objekat na koji this pokazuje
  2. novom objektu definise [[Prototype]]
  3. nastanjuje novi objekat svojstvima this.property = value
  4. vraca novi objekat
// konstruktor
function Person(name) {
this.name = name;
}

Person.prototype.talk = function() {
console.log('My name is ' + this.name);
};

// Funkcija imitira new
function newF(constructor, ...args) {
let obj = {};
Object.setPrototypeOf(obj, constructor.prototype);
constructor.apply(obj, args);
return obj;
}

var person1 = newF(Person, 'Ike');
// person1 = { name: 'Ike', __proto__: Person.prototype }

var person2 = new Person('Vana');
// person1 = { name: 'Vana', __proto__: Person.prototype }

person1.talk(); // My name is Ike
person2.talk(); // My name is Vana

Posudjivanje metode od prototipa:

Ispod zelimo metodu niza .join() primjeniti na objekat koji nije niz.

function person() {
console.log(arguments.join(' '));
// arguments.join is not a function
console.log(arguments.__proto__ === Object.prototype); // true
}

person('Ike', 'Barlowe');

arguments objekat sam po sebi je samo array-like, sto znaci da nije pravi niz (array) vec lici na njega jer ima indekse i length svojstvo. Po kreiranju za [[Prototype]] nasljedjuje Object.prototype i u svom prototipskom lancu nema metode koje rade sa nizovima.

Iz ovog razloga arguments.join(' ') izaziva gresku arguments.join is not a function. Medjutim, vecini metoda iz Array.prototype su samo potrebne vrijednosti sa indexima i svojstvo length, ne i da se radi o pravim nizovima. Problem je u tome sto arguments objekat nije kreiran kao niz i za prototip nije naslijedio Array.prototype od konstruktora. Prema tome je dovoljno da arguments objektu join() metodu ucinimo dostupnom.

person('Ike', 'Barlowe');

function person() {
arguments.__proto__ = Array.prototype;
// Arguments [[Prototype]] sada pokazuje na Array.prototype
console.log(arguments.join(' ')); // Ike Barlowe

console.dir(arguments);
}

Ispis arguments objekta u konzoli:

× Arguments(2)
    0: "Ike"
    1: "Barlowe"
  > callee: ƒ person()
    length: 2
  > Symbol(Symbol.iterator): ƒ values()
  × [[Prototype]]: Array(0)
     > at: ƒ at()
     > concat: ƒ concat()
       ...

Umjesto modifikovanja prototipa objekta, moguce je samo uvesti potrebnu metodu u objekat.

function person() {
arguments.join = Array.prototype.join
...
× Arguments(2)
    0: "Ike"
    1: "Barlowe"
  > join: ƒ join()
  > callee: ƒ person()
    length: 2
  > Symbol(Symbol.iterator): ƒ values()
  × [[Prototype]]: Object
     > constructor: ƒ Object()
     > hasOwnProperty: ƒ hasOwnProperty()
       ...

Prototip je i dalje ostao Object.prototype, a join() metoda radi.

Izracunata imena svojstava

U ovakvim funkcijama mozemo primjeniti jednu od super moci uglastih zagrada []. One pruzaju opciju da definisemo ime svojstva racunanjem (nije ograniceno na klase i konstruktore, isto se moze uraditi direktno u objektu).

function Konstruktor(key, value) {
this['Korisnikovo ' + key] = value;
}

let obj = new Konstruktor('Ime', 'Nina');
console.log(obj); // {Korisnokovo Ime: 'Nina'}

Gubljenje this i funkcija strelice

Jos jedan trik koji se moze izvesti u konstruktorima, klasama, ali ne i direktno u objektima.

Ukoliko neku metodu dodjelimo varijabli ona postaje nezavisna od objekta, zaboravlja na njegova ostala svojstva i this se gubi prilikom pozivanja takve funkcije. Ovo se cesto dogadja kada metodu proslijedimo funkciji kao argument.

function Konstruktor(fraza) {
this.fraza = fraza;

this.ispisiFrazu = function() {
console.log('Nova fraza: ' + this.fraza);
};
}

let obj = new Konstruktor('Dobar dan.');
let metoda = obj.ispisiFrazu;

metoda(); // Nova fraza: undefined

Pored poznatih rjesenja poput omotavanja metode u funkciju, koristenja bind metode, mozemo koristiti funciju strelice (arrow function () => {}).

// Omotavanje metode u funkciju.
let metoda = function() {
obj.ispisiFrazu();
};
metoda(); // Dobar dan

// Bind metoda.
let metoda = obj.ispisiFrazu.bind(obj);
metoda(); // Dobar dan

// Definisanje metode sa funkcijom strelice:
function Konstruktor(fraza) {
this.fraza = fraza;

this.ispisiFrazu = () => {
console.log('Nova fraza: ' + this.fraza);
};
}

let obj = new Konstruktor('Dobar dan.');
let metoda = obj.ispisiFrazu;

metoda(); // Nova fraza: Dobar dan

Ovo radi jer je vrijednost this u funkciji strelice odredjena na osnovu vanjskog leksickog opsega. Funkcija strelice nema svoj this kao obicna funkcija. Ovaj isti trik ne radi u objektima zbog leksickog opsega za this.

let obj = {
fraza: 'Dobar dan',
ispisiFrazu: () => {
console.log('Nova fraza: ' + this.fraza);
}
};

let metoda = obj.ispisiFrazu;

metoda(); // Nova fraza: undefined

Buduci da objekat ne stvara novi leksicki opseg, funkcija strelice ce traziti vrijednost za this izvan objekta.

let obj = {
vrijednostThis: this
};

console.log(obj); // {vrijednostThis: Window}

this pokazuje na Window globalni objekat u kom ne postoji svojstvo fraza i za rezultat JavaScript engine vraca vrijednost undefined.