Professional Documents
Culture Documents
Lect 01 - Programski Jezik JS
Lect 01 - Programski Jezik JS
programiranje
Školska 2021/22 godina
Zimski semestar
Blok 2
Lekcija 1: Uvod
Sadržaj predavanja
• Upoznavanje sa predmetom
• Raspored časova i nastavnici
• Cilj i sadržaj predmeta
• Plan izvođenja nastave
• Literatura i okruženje za praktičan rad
• Polaganje ispita i ocenjivanje
• Osnove jezika JavaScript
• Varijable, tipovi, operatori
• Kontrola toka programa
• Strukture podataka: objekat, niz
• Funkcije
• Kontekst izvršavanja
Raspored časova i nastavnici
• Blok: Blok 2
• Predavanja:
• ponedeljak, sreda, petak 10:00 – 12:00, prof. dr Stefana
Janićijević
• Vežbe
• Beograd
• ponedeljak, sreda, petak 12:00 – 14:00, Ass. Petar Jakić
• Konsultacije:
• Prof.dr Stefana Janićijević, utorak 17-18
• Ass. Petar Jakić
Cilj predmeta
• Da se razumeju osnove funkcionalnog stila
programiranja
• Da se razume deklarativni stil programiranja
• Da se nauči funkcionalno programiranje u
odabranom jeziku JavaScript
• Da se nauči kako praviti programe funkcionalnog stila
koristeći programski jezik JavaScript
• Da se proširi i produbi znanje jezika JavaScript:
• Da se osposobi za rutinsko programiranje u jeziku JavaScript sa
naglaskom na “out of browser JavaScript” aplikacijama
• Da se razume kako jezik JavaScript radi “ispod haube”
Sadržaj predmeta
• Programski jezik JavaScript – osnove
• Funkcionalno programiranje – koncepti, principi, i
teorijske osnove,
• Funkcionalno programiranje u jeziku JavaScript
Okruženje za praktičan rad
1. Chrome DevTools skup alata za izvršavanje
JavaScript koda u brauzeru
2. Node.js okruženje za izvršavanje JavaScript koda
van brauzera.
3. Babel JavaScript transkompajler za konverziju
ECMAScript 2015+ (ES6+) koda u ranije verzije
specifikacija (ako bude trebalo)
4. Mocha okruženje za testiranje
Literatura za predmet
1. Za JavaScript generalno
1. I. Kantor, PART 1 The JavaScript language, dostupno na: https://javascript.info/
2. Z. Konjović, Funkcionalno programiranje, slajdovi sa predavanja, dostupni na stranici predmeta
3. E. Elliot, Composing Software - An Exploration of Functional Programming and Object
Composition in JavaScript, Leanpub, 2019, Poglavlje “A Functional Programmer’s Introduction
to JavaScript”
2. Za JavaScript funkcionalno programiranje
1. K. Simpson, Functional-Light JavaScript - Balanced, Pragmatic FP in JavaScript, Manning, 2019
(prevod na srpski Z.Konjović, dostupno na stranici predmeta)
2. A. Aravinth, Beginning Functional JavaScript - Functional Programming with JavaScript Using
EcmaScript 6, Appress, 2017 (prevod na srpski, Z. Konjović, dostupno na stranici predmeta)
3. E. Elliot, Composing Software - An Exploration of Functional Programming and Object
Composition in JavaScript, Leanpub, 2019
4. Z. Konjović, Funkcionalno programiranje, slajdovi sa predavanja, dostupno na stranici predmeta
3. Priručnici za okruženja i slično
1. K. Basques, Get Started with Debugging JavaScript in Chrome DevTools, dostupno na
https://developers.google.com/web/tools/chrome-devtools/javascript (prevod na srpski Z.
Konjović, dostupan na stranici predmeta)
2. I. Kantor, Automated testing with Mocha, dostupno na: https://javascript.info/testing-mocha,
(prevod na srpski Z. Konjović, dostupan na stranici predmeta)
Polaganje ispita i ocenjivanje
• Ispit se sastoji iz 2 teorijska kolokvijuma (posle petog i desetog
termina) i 1 praktičnog zadatka (tokom ispitnog dela)
Delovi se boduju na sledeći način:
Kolokvijum 1 – 30
Kolokvijum 2 – 30
Praktični zadatak – 40
message = 123.456;
alert (message); // Ispis: 123.456
message = 'Sada sam string, a bila sam broj'
alert (message); // Ispis: Sada sam string, a
// bila sam broj
test1(); // Ispis:[object Object]
JS tipovi i strukture podataka
• Poslednja verzija ECMAScript standarda definiše
devet tipova klasifikovanih u 3 grupe
1. Primitivni tipovi
2. Strukturalni tipovi
3. Strukturalna korenska primitiva
JS primitivni tipovi
• U JavaScript-u, primitiva (primitivna vrednost, primitivni tip
podatka) je podatak koji nije objekat i nema metode. Ima ih 6:
• undefined : typeof instance === "undefined"
• Boolean : typeof instance === "boolean"
• Number : typeof instance === "number"
• String : typeof instance === "string"
• BigInt : typeof instance === "bigint"
• Symbol : typeof instance === "symbol„
• Sve primitive su imutabilne, t.j., ne mogu se menjati
• Ne sme se brkati sama primitiva sa varijablom kojoj je dodeljena
primitivna vrednost. Varijblama se može ponovo dodeljivati nova
vrednost, ali se postojeća vrednost ne može menjati na način na koji
se mogu menati objekti, nizovi i funkcije.
JS strukturalni tipovi
• Object : typeof instance === "object".
• Specijalni strukturalni (non-data) tip za svaku
konstruisanu instancu objekta koji se koristi i kao
strukture podataka: new Object, new Array, new Map,
new Set, new WeakMap, new WeakSet, new Date i
skoro sve ostalo što se pravi pomoću ključne reči new.
• Function : typeof instance === "function".
• Takođe non-data struktura, iako reaguje na typeof
operator: to je samo specijalna skraćenica za funkcije,
iako je svaki konstruktor funkcije izveden iza
konstruktora objekta.
JS strukturalna korenska
primitiva
• null : typeof instance === "object".
• Specijalni primitivni tip čija se vrednost dodatno koristi:
on je koren u lancu nasleđivanja objekata – svaki objekat
nasleđuje se od null tipa;
Konverzija tipova
• Različiti operatori i funkcije zahtevaju tačno određene tipove podataka
• Na primer, aritmetičke operacije zahtevaju podatke tipa number, operacije
ispisa zahtevaju podatke tipa string.
• Zbog toga je potrebno da se izvrši konverzija tipova, na primer:
• 1+2 = 3 => “3”
• “3”, “4” => 3+4
• Postoje situacije kada se mora izvršiti eksplicitna konverzija tipova, ali
većina operacija radi automatsku (implicitnu) konverziju tipova po
zadatim pravilima koja treba znati da ne bi bilo “iznenađenja”
• Posebno, treba proučiti pravila za konverziju tipa object u primitivne tipove
• Dobar izvor informacija o konverzijama je
https://javascript.info/type-conversions (za primitivne tipove) i
https://javascript.info/object-toprimitive (za konverziju tipa object u
primitivne tipove).
Operatori i operandi
• Operand je ono na šta se primenjuje operator
• 2+3
• Operatori:
• Unarni (primenjuje se na 1 operand):
• Znak - je negacija: let x = 1; x = -x;
• Znak + je konverzija u numeric: alert( +true ); // 1; alert( + "" ); // 0
• Binarni (primenjuje se na 2 operanda): let x = 1, y = 3; alert( y - x );
• Znak - je oduzimanje: let x = 1, y = 3; y = 3; alert( y - x ); // 2
• Znak + je sabiranje: let x = 1, y = 3; y = 3; alert( y + x ); // 4
• Znak + je konkatenacija stringova: let s = "my" + "string"; alert(s); // mystring
• Znak = je dodela vrednosti: let x = 1, y = 3;
• Za operatore je definisan redosled primene: 1 + 2 * 2 => 1 + (2*2)
• Sve o operatorima imate na https://javascript.info/operators
Operatori poređenja
• Operatori
• Veće/manje od: a > b, a < b.
• Veće/manje ili jednako od: a >= b, a <= b.
• Jednako: a == b.
• Nije jednako: a != b.
• Rezultat poređenja je uvek bulovski tip
• Stringovi se porede “slovo”-po-”slovo” leksikografskim
redosledom:
• ‘Ena' < ‘Ana'
• ‘Dobar' > ‘Dobra‘
• Detaljno o operatorima poređenja na
https://javascript.info/comparison
Logički operatori
• || (OR), && (AND), ! (NOT)
a b c = a ||b c = a &&b c = !a/c = !b Napomena
true true true true false/false
Prioritet
true false true false false/true operatora &&
je viši od
prioriteta
false true true false true/false operatora ||
• Više
false false false false true/true
alert("Ispravno!" );
alert( message );
Naredba switch:sintaksa
switch(x) {
case 'value1': // ako je (x === 'value1')
...
[break]
default:
...
[break]
}
Naredba switch:opcija break
let a = 2 + 2;
let a = 2 + 2;
switch (a) {
case 3: switch (a) {
alert('Premalo' );
case 3:
break;
case 4: alert('Premalo' );
alert(' Tačno!' ); case 4:
break; alert('Tačno!' );
case 5: case 5:
alert(' Preveliko' );
alert('Preveliko' );
break;
default: default:
alert(' Ne znam ' ); alert("Ne znam" );
} }
Petlje: while i do ... while
• while petlja: prvo se proverava uslov, pa se izvršava
telo
let i = 0;
while (i < 3) { // ispiši 0, pa 1, pa 2
alert( i );
i++;
}
}
Vidljivost brojačke varijable
• Ako je brojačka varijabla deklarisana u petlji, ona je vidljiva
samo u petlji:
for (let i = 0; i < 3; i++) {
alert(i); // ispisaće : 0, 1, 2
}
alert(i); // Ispisaće poruku o grešci:Uncaught ReferenceError: // i
is not defined at <anonymous>:4:7
alert(i); // 1, then 3, 5, 7, 9
}
• Može isto i bez continue:
for (let i = 0; i < 10; i++) {
if (i % 2) {
alert( i );
}
}
• A ovo ne može (continue nije dozvoljeno desno od ?):
(i > 5) ? alert(i) : continue; // continue ovde nije dozvoljeno
Labeliranje za
break/continue
• Koristi se za kada je potrebno istovremeno “iskočiti”
iz više petlji:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Vrednost u tački (${i},${j})`, '');
// Šta ako želimo da iskočimo na Done (iz petlje i i petlje j?)
}
}
alert('Done!');
// Prvi
const obj = {
log: ['a', 'b', 'c'],
get prvi() {
if (this.log.length === 0) {
return undefined;
}
return this.log[this.log.length - 3];
}
};
console.log(obj.prvi); // Izlaz: „a"
JS get funkcija
• Ponekad je poželjno da se dozvoli pristup svojstvu koje vraća dinamički
sračunatu vrednost, ili da se reflektuje status interne varijable bez
eksplicitnog poziva metode. U JS-u se to postiže korišćenjem getera
(getters).
• Sintaksa
{get prop() { ... } }
{get [expression]() { ... } }
• prop – ime svojstva koje će se vezati za zadatu funkciju.
• expression – Od ECMAScript 2015, mogu se koristiti i izrazi za sračunato ime
svojstva za vezivanje za zadatu funkciju.
• Nije dozvoljeno svojstvo koje istovremeno efektivno sadrži vrednost i
ima za sebe vezan geter.
• Geteri daju mogućnost da se svojstvo definiše ali njegovu vrednost ne
sračunavaju dok se svojstvu ne pristupi.
• Ako se svojstvu nikada ne pristupi, njegova vrednost se ni ne sračunava.
Definisanje getera: novi objekat
• Za nove objekte, u inicijalizatorima objekata
const obj = {
log: ['example','test'],
get latest() {
if (this.log.length === 0) return
undefined;
return this.log[this.log.length - 1];
}
}
console.log(obj.latest); // "test"
Definisanje getera: postojeći objekat
• Za postojeće objekte, pomoću metode
Object.defineProperty():
const o = {a: 0};
const obj = {
get [expr]() { return 'bar'; }
};
console.log(obj.foo); // "bar"
Sadržaj objekta: seteri
• Mehanizam setera povezuje svojstvo objekta sa funkcijom koja će biti
pozvana svaki put kada se pokuša postavljanje tog svojstva.
• JS sintaksa
{set prop(val) { . . . }}
{set [expression](val) { . . . }}
Parametri:
prop – ime svojstva za koje se vezuje data funkcija.
val - alias za varijablu koja sadrži vrednost koja se dodeljuje svojstvu prop.
expression – Od ECMAScript 2015, moguće je korišćenje izraza za
sračunavanje imena svojstva za koje će se vezati data funkcija.
• Kao i kod getera, nije dozvoljeno imati seter na svojstvu koje sadrži
aktuelnu vrednost.
• Seteri se najčešće koriste zajedno sa geterima za kreiranje neke vrste
pseoudo-svojstva.
Definisanje setera: nov objekat
const language = {
set current(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
console.log(language.log); // ['EN']
language.current = 'FA';
console.log(language.log); // ['EN', 'FA']
Definisanje setera: postojeći objekat
• Koristi se defineProperty():
const o = {a: 0};
Object.defineProperty(o, 'b', {
set: function(x) { this.a = x / 2; }
});
o.b = 10;
// Pokreće seter koji dodeljuje 10/2 (5)
// svojstvu 'a'
console.log(o.a) // 5
Seter: sračunato ime svojstva
const expr = 'foo';
const obj = {
baz: 'bar',
set [expr](v) { this.baz = v; }
};
console.log(obj.baz);
// "bar"
obj.foo = 'baz';
// pokretanje setera
console.log(obj.baz);
// "baz"
Brisanje getera i setera
• Koristi se operator delete:
delete language.current; // seter iz primera
delete obj.latest; // geter iz primera
Geteri i seteri: primer
var o = {
a: 7, // ovo je obična vrednost
get b() { // ovo je geter
return this.a + 1;
},
set c(x) { // ovo je seter
this.a = x / 2;
}
};
console.log(o.a); // 7
// sledeća linija pokreće get b() metodu
console.log(o.b); // 8
// Sledeća linija pokreće funkciju set c(x)
o.c = 50;
console.log(o.a); // 25
Operacije sa objektima: dodavanje i
brisanje svojstva
• Dve sintakse
// “tačkasta” sintaksa (postavlja svojstvo i njegovu vrednost)
let user = { // objekat
name: "John", // svojstvo "name" vrednost "John"
age: 30 // svojstvo "age" vrednost 30
};
alert( user.name);
alert( user.age);
// Brisanje svojstava (operator delete):
delete user.name
alert( user.name ); // undefined
alert( user.age ); // 30
console.log(objCopy); // rezultat - { a: 1, b: 2 }
objCopy.b = 89;
console.log(objCopy); // rezultat - { a: 1, b: 89 }
console.log(obj); // rezultat - { a: 1, b: 2 }
JS plitko kopiranje: problem
let obj = {
a: 1,
b: {
c: 2,
},
}
let newObj = Object.assign({}, obj); // obj plitko kopiran u newObj
console.log(newObj); // { a: 1, b: { c: 2} }
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
//(newObj netaknut!)
JS duboko kopiranje2
• Jedan problem:
JSON.parse(JSON.stringify(object)) ne
radi za metode objekta koje definiše korisnik
• Rešenje: to se može raditi sa Object.assign()
• https://www.digitalocean.com/community/tutorial
s/copying-objects-in-javascript
JS duboko kopiranje: Lodash
_.cloneDeep() metod1
• Lodash je jedna od JS biblioteka čija metoda _.cloneDeep() vrši rekurzivno
kloniranje.
const _ = require('lodash');
var obj = [{ x: 1 }, {y: 2}];
// Duboka kopija
var deepCopy = _.cloneDeep(obj);
console.log(Poređenje originala sa dubokom kopijom: ',
obj[0] === deepCopy[0]);
// Izmena originalne vrednosti
obj[0].x = 10;
Rezultat:
Poređenje originala sa dubokom kopijom: false
Nakon izmene originalne vrednosti obj[0].x = 10;:
Originalna vrednost: [ { x: 10 }, { y: 2 } ]
Duboka kopija vrednost: [ { x: 1 }, { y: 2 } ]
Plitko kopiranje: još primera
let user = { name: 'John' };
alert("user.name:" + user.name); // user.name je John
let admin = user; // kopiranje po referenci (user -> admin)
alert("admin.name:" + admin.name);// admin.name je John
myObject.a = 3;
myObject.a; // 2
Deskriptor: configurable
• Sve dok svojstvo ima karakteristiku da je
konfigurabilno (vrednost deskriptora configurable
je true), moguće je modifikovati definiciju
deskriptora pomoću defineProperty(..).
• configurable:false znači da više nema menjanja
• Promena configurable na false je jednosmerna
akcija i ne može se opozvati!
• Takođe, configurable:false sprečava mogućnost
da se koristi delete operator za uklanjanje
postojećeg svojstva.
Deskriptor: enumerable
• Ova karakteristika kontroliše da li će se svojstvo
pojavljivati u konstruktima sa nabrajanjima svojstva
u objektu, kao što je for..in petlja.
• Vrednost svojstva false znači da se ono neće
pojavljivati u takvim nabrajanjima, iako je inače
potpuno dostupno.
• Naravno, vrednost true znači da će se pojavljivati u
takvim nabrajanjima.
Strukture podataka: Array1
• Tip Array (niz) je specijalni tip objekta koji služi za
skladištenje uređenih kolekcija vrednosti gde se
pojedinačnim elementima kolekcije može pristupati
putem pozicije (indeks).
• Deklarisanje – dve sintakse za kreiranje praznog niza:
let arr = new Array(); - vrlo retko se koristi
let arr = []; - najčešće se koristi
• Dodela vrednosti elementima može da se radi u
deklaraciji i van deklaracije
• Početna vrednost indeksa je 0.
Strukture podataka: Array2
• Ukupan broj elemenata u nizu čuva se u svojstvu length što predstavlja
vrednost poslednjeg numeričkog indeksa uvećanu za 1 (može da bude i
“praznih” elemenata između):
// U deklaraciji
let fruits = ["Apple", "Orange", "Plum"];
alert (fruits.length)// 3
alert (fruits) // Apple Orange Plum
// Van deklaracije
fruits [3] = "Grape"
alert (fruits.length) // 4
alert( fruits); // Apple Orange Plum Grape
fruits [9] = "Pear"
alert (fruits.length) // 10
alert( fruits);
// Apple Orange Plum Grape ,,,,,,Pear
Deklarisanje niza: ključna reč
new
• Sintaksa je:
let arr = new Array("Apple", "Pear", "etc");
• Sintaksa se retko koristi, jer ima “škakljivo” svojstvo: Ako se new
Array pozove sa jednim argumentom koji je broj (number),
poziv kreira niz bez elemenata ali sa zadatom dužinom
(length).
let arr = new Array(2); // da li će kreirati [2] ?
alert( arr[0] ); // undefined! Nema elemenata.
alert( arr.length ); // a dužina 2
• Ako nije number, radi uredno:
let arr = new Array("2"); // da li će kreirati ["2"] ?
alert( arr[0] ); // 2! Ima element koji treba.
alert( arr.length ); // a dužina 1
Strukture podataka Array : operacije
• Kraj niza
• push(...stavke) dodaj na kraj i vrati.
• pop() ukloni sa kraja.
let fruits = ["Apple", "Orange", "Pear"];
alert( fruits ); // Apple, Orange, Pear
fruits.pop(); // ukloni "Pear"
alert( fruits ); // Apple, Orange
fruits.push ("Plum") // dodaj "Plum" na kraj
alert( fruits ); // Apple, Orange, Plum
Strukture podataka Array : operacije
• Početak niza
• shift() ukloni sa početka i vrati:
let fruits = ["Apple", "Orange", "Pear"];
alert( fruits ); // Apple, Orange, Pear
fruits.shift(); // ukloni Apple
alert( fruits ); // Orange, Pear
function ime([parametri]) {
...telo... }
Telo funkcije
(šta funkcija radi)
function kaziZdravo() {
alert('Pozdrav svima!' );
}
Deklaracija funkcije: Funkcijski izraz
• Druga sintaksa za kreiranje funkcije je funkcijski izraz
( Function Expression).
• U ovoj sintaksi, funkcija se kreira i eksplicitno dodeljuje
varijbli - nije važno kako je funkcija definisana, ona je
samo vrednost smeštena u neku varijablu.
let kaziZdravo = function () {
alert('Pozdrav svima!' );
};
• Funkcijska naredba ima obavezan simbol ; na kraju, a u
funkcijskoj deklaraciji on nije obavezan.
Deklaracija funkcije: Imenovani funkcijski
izraz
• Funkcijski izraz deklariše anonimnu funkciju
(funkciju bez imena)
• Imenovani funkcijski izraz može da deklariše
neanonimnu funkciju (funkciju sa imenom)
• To ime je lokalno, važi samo u telu funkcije
• Omogućuje referisanje funkcije imenom u telu funkciji
(pogodno za rekurziju)
Imenovani funkcijski izraz:
primer
let math = {
'factit': function factorial(n) {
console.log(n)
if (n <= 1) {
return 1;
} return n * factorial(n - 1);
}
};
math.factit(3) //3;2;1;
Deklaracija funkcije i ime
• Varijabla kojoj se dodeli funkcijski izraz ima svoje ime.
• Ime funkcije se ne menja ako se ona dodeljuje
različitim varijablama.
• Ako se ime funkcije izostavi (neimenovani funkcijski
izraz) ime funkcije će biti isto kao ime varijable
(implicitno ime)
• Ako je ime funkcije prisutno, to će biti ime funkcije
(eksplicitno ime)
• Ovo važi i za streličastu sintaksu (o njoj ćemo kasnije)
Deklaracija funkcije i ime:
primer
var foo = function(){}
console.log(foo.name) // "foo "
var foo2 = foo
console.log(foo2.name) // "foo "
var bar = function baz() {}
console.log(bar.name) // "baz"
console.log(foo === foo2);// true
console.log(typeof baz); // undefined
console.log(bar === baz); // greška jer je
// baz == undefined
Pozivanje funkcije
• Da bi funkcija uradila svoj posao, ona se mora pozvati
• Funkcija se poziva navođenjem imena i vrednosti prametara (argumenti):
• Primer 1 (funkcija bez argumenata):
function showMessage() {
alert('Pozdrav svima!' );
}
showMessage(); // Pozdrav svima!
a + b;
}
2. Funkcijski izraz: reč function unutar izraza ili drugog sintaktičkog kostrukta. Na primer,
funkcija kreirana na desnoj strani “izraza dodele” =:
// Function Expression
let sum = function(a, b) {
return a + b;
};
Za ovakvu sintaksu dozvoljeno je korišćenje u konstruktu Block ({ ... }) u naredbama
if, while ili for.
Kada endžin kreira funkciju
• Funkcijski izraz se kreira kada se u izvršenju dođe do njega i
upotrebljiv je tek od tog momenta.
sayHi("Pero"); // greška – ovde još ne može!
function sayHi(name) {
alert( `Zdravo, ${name}` );
}
Blokovsko dosezanje1
• U režimu strict, kada je kanonička deklaracija unutar bloka
koda, vidljiva je unutar toga bloka a nije vidljiva izvan bloka:
"use strict";
let age = prompt("Koliko Vam je godina?", 18);
// Uslovno deklarisanje funkcije (u bloku)
if (age < 18) {
function welcome() {
alert("Hello!");
}
} else {
function welcome() {
alert("Greetings!");
}
}
// ...a poziva se izvan bloka
welcome(); // Greška: funkcija welcome nije // definisana
Blokovsko dosezanje2
"use strict";
let age = 16; // uzmimo 16 za primer
if (age < 18) {
welcome(); // \ (radi)
function welcome() { // |
alert("Ćao!"); // | Funkcija welcome je dostupna
} // | u bloku u kome je deklarisana
welcome(); // / (radi)
} else {
function welcome() {
alert("Dobar dan!");
}
}
// A ovde smo izvan bloka (crvene vitičaste zagrade),
// pa ne vidimo deklaraciju funkcije welcome koja je unutar bloka.
welcome(); // Zato dobijamo grešku: welcome is not defined
Kako to popraviti: funkcijski izraz sa let
deklaracijom i dodela u bloku
"use strict";
let age = prompt("Koliko Vam je godina?", 18);
let welcome; // deklaracija izvan bloka
if (age < 18) {
welcome = function() {
alert("Ćao!");
};
} else {
welcome = function() {
alert("Dobar dan!");
};
}
welcome(); // ovo sada radi
Kako to popraviti: funkcijski izraz drugi
način – sa uslovnim izrazom (?)
"use strict";
let age = prompt("Koliko Vam je godina?",
18);
Uvek može da postoji SAMO JEDAN globalni kontekst i PROIZVOLJAN (konačan) BROJ
funkcijskih konteksta
Koliko ima globalnih, a koliko funkcijskih konteksta ovde?
Evaluiranje koda: stek konteksta izvršavanja
• JavaScript endžin je u brauzeru implementiran kao jedna nit pa je i stek sa jednom
niti: To znači da se u brauzeru u jednom trenutku može dešavati samo jedna stvar
a ostale stvari se smeštaju u red čekanja koji se zove Stek izvršavanja:
Evaluiranje koda: stek konteksta izvršavanja
• Kada brauzer prvi put napuni skript, on ulazi u globalni
kontekst izvršavanja po pretpostavci.
• Kada se u kodu poziva funkcija, sekvenca toka programa ulazi
u pozvanu funkciju i pri tome kreira novi kontest izvršavanja
koji postavlja na vrh steka izvršavanja.
• Kada se pozove druga funkcija unutar tekuće funkcije,
dešava se ista stvar. Tok izvršavanja ulazi u unutrašnju
funkciju koja kreira novi kontekst izvršavanja koji se postavlja
na vrh postojećeg steka.
• Brauzer će uvek da izvršava tekući kontekst izvršavanja koji će
skidati sa vrha steka i vraćaće kontrolu kontekstu koji je ispod
u tekućem steku.
Stek konteksta izvršavanja:
primer
(function foo(i) {
alert(i)
if (i === 3) {
return;
}
else {
foo(++i);
}
}(0));
Stek konteksta izvršavanja:
kreiranje
Globalni kontekst
Stek konteksta izvršavanja:
ažuriranje steka pri izvršavanju
Globalni kontekst
Ključne stvari konteksta
izvršavanja
1. Jedna nit.
2. Sinhrono izvršavanje.
3. Jedan globalni kontekst.
4. Više (konačno mnogo) funkcijskih konteksta.
5. Svaki poziv funkcije kreira novi kontekst, čak i
rekurzivni poziv (kada funkcija poziva samu sebe).
JS kontekst izvršavanja: konceptualni
model
• Svaki kontekst izvršavanje se može konceptualno predstaviti
kao objekat sa tri svojstva (koja u i sama objekti):
executionContextObj = {
'scopeChain': { /* variableObject + svi
variableObject-i roditeljskih konteksta izvršenja
*/ },
'variableObject': { /* argumenti funkcije /
parametri, unutrašnje deklaracije varijabli i
funkcija */ },
'this': {}
}
Detalji JS konteksta
izvršavanja
• Svaki put kada se pozove funkcija, kreira se novi
kontekst izvršavanja
• Faza 1 - kreiranje: dešava se kada se funkcija
pozove, ali pre izvršavanja bilo kakvog koda unutar
funkcije
• Faza 2 – aktivacija/izvršavanje: dodeljuju se
vrednosti referenci funkcijama i kod se
interpretira/izvršava.
JS kontekst izvršavanja: Faza 1
1. Kreira se lanac dosezanja (Scope Chain).
2. Kreiraju se varijable, funkcije i argumenti.
3. Određuje se vrednost pokazivača this.
JS kontekst izvršavanja: Objekat
executionContextObj1
foo = 'abc';
alert(foo); // Ispis: abc
this.foo = 'def';
alert(foo); // Ispis: def
JS this u funkcijskom
kontekstu
var boat = {
size: 'normal',
boatInfo: function() {
alert(this === boat);
alert(this.size);
}
};
boat.boatInfo(); // Ispis: true, 'normal'
var bigBoat = {
size: 'big'
};
bigBoat.boatInfo = boat.boatInfo;
bigBoat.boatInfo(); // Ispis: false, 'big'
JS this u funkcijskom
kontekstu
• U JS-u vrednost ključne reči this unutar funkcije
nije statična, ona se određuje svaki put kada se
funkcija pozove, ali pre no što se stvarno izvrši kod
funkcije.
• Vrednost za ključnu reč this unutar funkcije u
stvari obezbeđuje roditeljski doseg u kome je
funkcija pozvana, i što je još važnije način na koji je
sintaksa funkcije napisana.
JS this u funkcijskom
kontekstu
• Pri pozivu funkcije, mora se obratiti pažnja na neposrednu levu
poziciju od zagrade “()”:
• Ako na levoj strani postoji referenca, vrednost this prosleđena funkcijskom
pozivu je pokazivač na objekat kome taj metod pripada.
• U protivnom, this pokazuje na globalni objekat.
function bar() {
alert(this);
}
bar(); // globalni - zato što metod bar() pripada globalnom //
objektu
var foo = {
baz: function() {
alert(this);
}
}
foo.baz(); // foo - zato što metod baz() pripada objektu foo
JS this : sintaksa poziva
• Ključna reč this može se menjati i u samoj funkciji:
var foo = {
baz: function() {
alert(this);
}
}
// prva sintaksa poziva
foo.baz(); // foo - zato što metod baz pripada objektu foo //
pri pozivu
</body>
</html>
JS this : eksplicitno
postavljanje
• Radi se pomoću funkcija call() i apply():
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + ","
+ country;
}
}
var person1 = {
firstName:"Pera",
lastName: "Perić"
}
var person2 = {
firstName:"Mika",
lastName: "Perić"
}
console.log (person.fullName.apply(person1, ["Beograd", "Srbija"]));
console.log (person.fullName.call(person2, "Novi Sad", "Srbija"));
Literatura za predavanje
1. Z. Konjović, Funkcionalno programiranje, Uvod,
slajdovi sa predavanja, dostupni na stranici predmeta
2. I. Kantor, PART 1 The JavaScript language, dostupno
na: https://javascript.info/
3. E. Elliot, Composing Software - An Exploration of
Functional Programming and Object Composition in
JavaScript, Leanpub, 2019, Poglavlje “A Functional
Programmer’s Introduction to JavaScript”
4. Debgging JavaScript in Chrome DevTools, dostupno na
https://developers.google.com/web/tools/chrome-dev
tools/javascript
(prevod na srpski Z. Konjović, dostupan na stranici
predmeta)
Sažetak
• JavaScript je programski jezik koji može da se koristi u brauzeru (klijentsko
skriptovanje), ali i van brauzera (skriptovanje na serverskoj strani)
• U JavaScript-u funkcije su građani prvog reda; mogu se prosleđivati
drugim funkcijama, mogu da vrate drugu funkciju kao povratnu vrednost,
mogu se komponovati, itd.
• Kontekst izvršavanja JavaScript-a ima sledeće bitne odlike:
• Jedna nit.
• Sinhrono izvršavanje.
• Jedan globalni kontekst.
• Više (konačno mnogo) funkcijskih konteksta.
• Svaki poziv funkcije (čak i rekurzivni) kreira novi kontekst.
• JavaScript je slabo tipiziran jezik, ali ipak ima 9 tipova (6 primitivnih i 3
strukturalna).
• U JavaScript-u, varijabli se može dodeliti podatak bilo kog tipa (nema tipa
varijable, ima samo tip podatka).
• U stvari, u JavaScript-u skoro sve je objekat
• U većini slučajeva, operatori/funkcije vrše implicitnu koerciju podataka i treba
znati pravila po kojima se to radi.