Funkcije su objekti

Postoji osam osnovnih tipova podataka u JavaScript-u. Sedam od njih su primitivni tipovi podataka (poput brojeva, teksta itd.) i osmi je neprimitivni tip — objekat, a funkcije su prvoklasni objekti koji se mogu pozvati sa zagradama () kako bi izvrsili naredbu / akciju. Drugim rijecima, moguce je raditi sa funkcijama kao sa objektima.
function sayHi() {
console.log('Greetings');
}
sayHi(); // Greetings
console.log(typeof sayHi); // function
console.log(sayHi instanceof Object); // trueSvojstva objekta
Funkcija moze biti korisna sama po sebi i nositi bezbroj dodatnih funkcionalnosti u svojstvima.
Jedna od osobina koju funkcije dijele sa objektima su svojstva (key: value parovi i metode) koje im se mogu kreirati, modifikovati i brisati. Za one koji nisu upoznati sa ovim tipom podatka, ispod je definisan objekat sa jednim key: value parom, da bi izvan objekta pristupili tom svojstvu i izmjenili njegovu vrijednost.
let sum = {
current: 0;
};
sum.current = 3 + 5; // modifikuje vrijednostA ovako izgleda funkcija sum() kojoj smo dodijelili isto svojstvo koristeci tacku sum.current.
function sum(a, b) {
sum.current = a + b; // sum.current nije varijabla
}
sum.current = 0; // definisano svojstvo objekta funkcije
sum(3, 5);
console.dir(sum); // prikazuje svojstva objektaRezultat koda u konzoli:

sum() svojstava.Kako je ona poseban tip objekta, dodijeljena su joj neka korisna svojstva koji drugi tipovi objekata nemaju. U konzoli su prikazani sa tamnijim slovima (arguments, caller, length, name itd.). Current svojstvo nije doslo sa funkcijom, definisano je u kodu.
Duzina parametara funkcije
length svojstvo se odnosi na definisan broj parametara koje funkcija prihvata:
function add(a, b) {
return a + b;
}
console.log(add.length); // 2Kontekstualno ime
Name svojstvo, kako ocekujemo, daje pristup imenu funkcije.
function add(a, b) {
return a + b;
}
console.log(add.name); // addCak i kada se radi o varijabli kojoj je po kreiranju dodjeljena funkcija bez imena, svojstvo name ce zakljuciti ime iz konteksta.
let add = function(a, b) {
return a + b;
};
console.log(add.name); // addKoje ime ce imati izraz funkcije (function expression) ako varijabli dodijelimo funkciju sa imenom?
let add = function calculate(a, b) {
return a + b;
};
console.log(add.name); // calculateIli ako funkcija nije dodijeljena varijabli i nema ime?
let func = [function() {}];
console.log(func[0].name); // *crickets chirping*
console.dir(func[0]);
// ƒ anonymous()
// arguments: null
// caller: null
// length: 0
// name: ""
// prototype: {constructor: ƒ}Prioritet uvijek ima ime deklarisano nakon kljucne rijeci function, a ako ga uopste nema - onda se radi o anonimnoj funkciji sa name: "" (vrijednost je prazan string).
Imenovani funkcijski izrazi
Deklaracija funkcije (function declaration) uvijek pocinje sa function imeFunkcije() {...}, dok izraz funkcije (function expression) omogucava kreiranje nove funkcije unutar bilo kog izraza.
let func = function() {
// ...
};Ovo je jedan primjer izraza funkcije jer se kreiranje funkcije desava u sklopu izraza — kroz dodjeljivanje anonimne funkcije varijabli. Izrazi zavrsavaju sa ; da bi kompajler razlikovao i odvojio izraze. Funkcija nema ime i name svojstvo ove funkcije je izvuceno iz konteksta (varijable func).
Da bi kreirali imenovani funkcijski izraz (Named Function Expression), varijabli func treba dodijeliti imenovanu funkciju:
let func = function read() {
// ..
}
console.log(func.name); // readKljucna stvar kod ovakve funkcije je da ona rezervise read identifikator za unutrasnji opseg i predstavlja pouzdan nacin za pozivanje sebe. Pouzdan je jer se taj identifikator ne moze izmjeniti nakon kreiranja funkcije, cak i ako se promijeni ime varijable. Ali read identifikator je pogodan za interno pozivanje sebe jer nije dostupan izvan funkcije, dok je func ime varijable dostupno unutar i izvan funkcije i njeno ime se moze izmjeniti.
let func = function read(quote) {
if (quote) {
console.log(quote);
} else {
read("Lorem ipsum dolor sit amet.");
// poziva sebe sa argumentom
}
};
func(); // Lorem ipsum...
read();
// Uncaught ReferenceError: read is not definedMetode funkcije
Kao i objekti, funkcije mogu imati metode, a neke su predefinisane (console.dir(add)):
ƒ add(a, b)
arguments: null
caller: null
length: 2
name: "add"
[[Prototype]]: ƒ ()
bind: ƒ bind()
toString: ƒ toString()
Symbol(Symbol.hasInstance): ƒ [Symbol.hasInstance]()
get arguments: ƒ ()
...
func.toString() u konzoli vraca tijelo funkcije kao string.

toString() primjenjena na funkciji u konzoli.Mnoge JavaScript biblioteke koriste ovu osobinu funkcija. jQuery biblioteka ima glavnu funkciju $ i ostale pomocne funkcije koje se vezu za nju. Na ovaj nacin se izbjegava preopterecenje globalnog prostora i konflikti imenovanja varijabli i funkcija.
Prosljedjivanje po referenci
One se prosljedjuju po referenci (pass by reference) kao i drugi objekti (array i object), dok se primitivni tipovi podataka (svi ostali) prosljedjuju po vrijednosti. Ovdje je detaljnije objasnjeno sta to znaci i kako se razlikuju.
U sustini, kada varijabli dodijelimo funkciju, ona ne dobija kopiju funkcije, vec referencu koja pokazuje na mjesto u memoriji gdje se ona nalazi. Tako dvije varijable imaju razlicita imena iako pristupaju istoj funkciji.
let book = function() {
// ...
}
var book2 = book;
book.author = "Ana";
console.log(book.author); // Ana
console.log(book2.author); // Ana
book2.author = "Vana";
console.log(book.author); // Vana
console.log(book2.author); // VanaFunkcije se mogu prosljedjivati kao argumenti drugim funkcijama. I u ovom slucaju argumenti su referenca na funkciju, ne njena kopija.
function calculate(callback, x, y) {
let result = callback(x, y);
console.log(result);
}
function add(x, y) {
return x + y;
}
function multiply(x, y) {
return x * y;
}
calculate(add, 2, 3); // => 5
calculate(multiply, 2, 3); // => 6