1.37k likes | 1.55k Views
Realizacja Aplikacji Internetowych. JavaScript. Quiz. [] + [] [] + {} [0]+1 [0]-1 A = [0] A == A A == !A A = [null, undfined, [] ] A == ”,,”. JavaScript vs ECMAScript. JavaScript is nie jest związany z Javą Wprowadzony w przegladarce Netscape w XII 1995
E N D
Realizacja Aplikacji Internetowych JavaScript
Quiz • [] + [] • [] + {} • [0]+1 • [0]-1 A = [0] • A == A • A == !A A = [null, undfined, [] ] • A == ”,,”
JavaScript vs ECMAScript • JavaScript is nie jest związany z Javą • Wprowadzony w przegladarce Netscape w XII 1995 • Najbardziej popularny język programowania na świecie ? • MS wyprodukował zbliżony język: JScript • Oba języki bazują na standardzie ECMAScript wprowadzonym przez European Computer Manufacturers Association (3 wyd w XII 1999) • JavaScript i JScript są nadzbiorami ECMAScript • Są hostowane w przeglądarkach, ale nie tylko (Acrobat Forms, Node.js)
Typy • Undefined(pojedyncza wartość: undefined) • Null(pojedyncza wartość: null) • Boolean(wartości: true, false) • String(niemutowalna sekwencja znaków Unicode, brak typu znakowego) • Number (64-bitowa liczba zmiennoprzecinkowa, brak typu całkowitego, specjalne wartości NaN i Infinity) • Object • "...i to by było na tyle...".
Nowe operatory • ===jest identyczny (wartość i typ) • !==nie jest identyczny (wartość lub typ)
Zmienne • Dwa poziomy granularności zakresu: globalne i funkcja (brak zakresu bloku) • Tylko zmienne defioniowane jako varw obrebie funkcji mają zakres funkcji – inne są globalne. Nie na sensu używać bloków gdy nie są wymagane przez instrukcje złożone. • varnie zaincjalizowane ex-plicite ma wartość undefined. • varnie jest typowane
Obiekty • Referencjonalne kontenery par nazwa/wartość • Nazwy: napisy (Jeśli treba wykonywan konwersja) • Wartości: dowolny typ danych (właczajac inne obiekty) • Nie trzeba implementować dostępu API (hashtable) • Właściwości tworzone w locie var myObj={}; var myObj=new Object(); myObj.p1=”blah” ; myObj[”p1”]=”blah”; var myObj={”p1”:new String(”blah”)}; • Metody ?
Obiekty Obiekty są w istocie tablicami haszowanymi z ładną składnią Można więc iterować po obiekcie... for (name in object) { if (object.hasOwnProperty(name)) { value = object[name]; } }
Obiekt Globalny • Unikalny, pre-definiowany obiekt który zawiera wszytskie funkcje i zmienne nie zdefionowane wewnątrz innych funkcji lub obiektów • W przeglądarkach implementacja this, windowi selfpokazują na Obiekt Globalny • Wszystkie globalne funkcje i zmienne są zdefiniowane jako funkcje i zmienne Obiektu Globalnego this.NaN=0; //changes value of NaN ‘constant’ ! • Jeśli zmienna/funkcja nie jest zdefiniowana w bieżącym zakresie jest poszukiwana w Obiekcie Globalnym
Tablice • Regularne obiekty (właściwości dostępne za pośrednictem nazw!) properties accessed via names!), ale okreslona klasa nazw (non-negative integers) właściwości traktowana inaczej • Nie typowane (mogą zawierać wartości różnych typów) • Właściwość length jest ustawiana na największy klucz całkowity w tablicy +1 var myArr=[”val0”]; //myArr.length == 1 myArr[1]=”val1”; //myArr.length == 2 myArr[”v2”]=”val2”; //myArr.length == 2 myArr.2=”val2”; //nielegalne
Funkcje • Obiekty typu first-class ze skojarzonym kodem i możliwą operacją call • Składniafunction func(x) {alert(x);} • Operator (nazwa f. jest opcjonalna – f.anonimowe) var func=function(x) {alert(x);}; • Konstruktor (nie ma słowa function) var func=new Funkcja(”x”,”alert(x);”); • Wsparcie dla zmiennej liczby argumentów (właściwość arguments) • Ma zakres leksykalny
Funkcje (c.d.) • Mogą być przypisywane do zmiennych (wcześniejszy przyklad) • Mogą być elementami tablicy var arr=[]; arr[0]=function(x){return x*x;}; arr[1]=arr[0](2); alert(arr[1]); //displays 4 • Mogą mieć swoje właściwości var func=function(x) {alert(x);} func.ownProperty=”test”; • Mogą być właściwościami obiektu (metody!) var obj={”show”: function(){return ”-object-”;}} alert(obj.show()); //displays -object-
Funkcje (c.d.) • Mogą być przekazywane jako argumentfunction square(x) {return x*x;}function opOn(num,func) { return func(num);} opOn(16,square); //displays 256 • Mogą być zwracane jako wartość function createIncrementer() { return function(x){return x+1;} } var inc = createIncrementer(); alert(inc(7)); //displays 8 • Muszą zwracać wartość (domyślnie jest to undefined, z wyjątkiem wołań operatora new)
Metody • Metoda jest funkcją wołaną z kontekstem określonego obiektu • Metody mogą być definiowane przez : • Ustawienie funkcji jako właściwości obiektu myObject.method1=function(...){...} myObject.method1(...) • Ex-plicite wskazany kontekst myFunction.call(myObject,...) • Specjalna zmienna thisjest dostępna wewnątrz funkcji i odnośi się do obiektu wskazanego jako kontekt (lub Obiektu Globalnego dla f. niezwiązanych)
Operator new i konstruktory • operator newjest używany wraz z wywolaniem funkcji: • Tworzy nowy pusty obiekt • Ustawia go jako thisdla wywołanej funkcji • Ustawia go jako domyślny zwrot z funkcji (może być nadpisany) • ... • Jeżeli f. Jest użyta do ustawienia właściwości nowego obiektu wraz z operatoem newmoże być uznana (i jest nazywana) konstruktorem function func() {this.prop1=”val1”;} var x=new func(); alert(x.prop1); //displays val1
Realizacja Aplikacji Internetowych Wielkie udawanie
OOP Emulacja metod • Metody mogą być definiowane przez ustawienie właściwości na daną funkcję myObj1.func=function(){alert(this.name);}; • Połączenie obiekt-metoda jest b. słabe var myObj1={”name”:”obj1”}; var myObj2={”name”:”obj2”}; myObj1.func=function(){alert(this.name);}; myObj1.func(); //displays obj1 myObj1.func.call(myObj2); //displays obj2
OOP Emulacja klas • Konstruktory definiują sposób tworzenia obiektu (OOP klasy) function myConstructor(value) { this.prop1=value; this.check=function(val) { if(this.prop1==val) alert(”ok!”); } } var myObj1=new myConstructor(”obj1”); myObj1.check(”obj1”); //displays ok! myObj1.check(”obj2”); //do nothing
OOP Emulacja klas (c.d.) • Obiekty mogą współdzielić implementację swoich metod function checkFunction(val) { if(this.prop1==val) alert(”ok!”); } function myConstructor(value) { this.prop1=value; this.check=checkFunction; } var myObj1=new myConstructor(”obj1”); myObj1.check(”obj1”); //displays ok!
OOP Emulacja klas (c.d) • Konstruktor (funkcja) nie jest związany z żadnym typem • Każda funkcja może być wywołana jako konstruktor var myObj1={”name”:”obj1”}; myObj1.func=function() { alert(this.name); return {}; }; var x=new myObj1.func(); //x is empty object • Obiektynadpisujądomyslnyzwrot z funkcji. Typyprostejużnie.
OOP emulacja metod statycznych • Ponieważ funkcja konstruktor faktycznie reprezentuje klasę obiektów i może być rozszerzna o własne właściwości implementacja metod i właściwości statyczny jest trywialna function BaseClass(name){ this.name = name; } BaseClass.staticMethod = function() { return new OtherClass(); }; ... var other = BaseClass.staticMethod();
Mamy obiekt i chcielibyśmy mieć drugi - podobny… Application.GUI.Panel; ... Application.GUI.SecondPanel = Application.GUI.Panel; // this is in fact the same object!!! //What about Application.GUI.SecondPanel.Name = “Second”; //What is the name of the first panel? Application.GUI.Panel.Name = ???
Klony nadchodzą Funkcje są obiektami imożna je kopiować! Application.GUI.Panel; ... App.GUI.SecondPanel = {}; App.GUI.SecondPanel.Show = App.GUI.Panel.Show; App.GUI.SecondPanel.Validate = App.GUI.Panel.Validate; //and many, many more…. //what about ? App.GUI.SecondPanel.Config = App.GUI.Panel.Config;
Helper z ExtJS? //this copies all the stuff (including functions) //from Panel to SecondPanel Ext.apply(Application.GUI.SecondPanel,Application.GUI.Panel) // Exemplary implementation Ext.apply = function(d, e, b) {if (d && e && typeof e == "object") {for (var a in e) {d[a] = e[a]}}return d }; • Issues: • shallow copy • prototypes
OOP Emulacja dziedziczenia – podejście funkcyjne function Base(name){ this.name = name; } var b = new Base("b1"); alert(b.name); //displays b1 //class Derived : Base function Derived(name,count) { Base.call(this,name); //this.baseClass=Base; this.count = count; //this.baseClass(); } var d = new Derived("d1",5); alert(d.count); //displays 5 alert(d.name); //displays d1
Prototypy • Każda funkcja ma właściwość prototype wskazującą na obiekt (domyślnie pusty) • Każdy obiekt (włączając funkcje) ma właściwość constructor. Obiekt wskazywany domyślnie przez prototype danej funkcji ma swoją właściwość constructor ustawioną na pierwotną funkcję • Property constructororaz prototype można nadpisać.
Prototypy (c.d.) • Obiekty nie-funkcyjne mają ukrytą (niedostępną) właściwość _prototype, która pokazuje na prototyp (obiekt), który obowiązywał (wskazywało na niego prototype w konstruktorze) w momencie tworzenia obiektu. • Operator newaktualizuje tworzony obiekt: • Ustawia wlaściwość _prototypena prototype konstructora
Emulacja dziedziczenia (c.d.) Łańcuch dziedziczenia po utworzeniu jest stabilny Derived.prototype=new Base1(); var d1=new Derived(...); //d1 cannot be altered to inherit //from object other than Base1 ...ale można go zmienić dla nowych obiektów Derived.prototype=new Base2(); var d2=new Derived(...); //d1 and d2 inherit from //different objects
Prototypy (c.d.) • Jeżeli obiekt nie implementuje żadanej właściwości,sprawdzany jest jego prototyp, stąd: • Obiekt efektywnie "dziedziczy" wszystkie własciwości po swoim prototypie • Zmiany w prototypie są natychmiast widoczne w obiektach potomnych (równiez już utworzonych) • Każda wartość w prototypie może być "nadpisana" w obiekcie • Obiekty potomne mogą być prototypami innych obiektów, tworząc łańcuch dziedziczenia (aż do Obiektu Globalnego) • Ponieważ własciwości są tworzone w locie, obiekty pochodne w momencie zapisu do dziedziczonej (z _prototype) wartości automatycznie tworzą własną kopię ("nadpisując" dziedziczoną wartość)
Dziedziczenie na poziomie obiektu? InheritFromObject (objectToDerrive) { var f = function() {}; f.prototype = objectToDerrive; return new f(); } App.GUI.Panel; ... App.GUI.SecondPanel = InheritFromObject(App.GUI.Panel); // albo nawet zeskładniązbliżoną do f. wbudowanych Object.prototype.BegetObject = function () { var f = function() {}; f.prototype = this; return new f(); } App.GUI.Panel; ... App.GUI.SecondPanel = App.GUI.Panel.BegetObject();
Dziedziczenie na poziomie obiektu Ale: • Object jest globalny więc begetObject może być nadpisane • Co będzie jak oldObject się zmieni?
Zmiany: App.GUI.Panel; ... App.GUI.SecondPanel = App.GUI.Panel.BegetObject(); //some behaviors and attributes can be overwritten App.GUI.SecondPanel.Show = function() {}; App.GUI.SecondPanel.Title = “new panel”; Co będzie w momencie zmiany w App.GUI.Panel ?? Application.GUI.Panel.Validate = function() {}; //they will cause change in behavior SecondPanel in //case when the Hide function wasn’t overridden
Emulacja dziedziczenia klas – podejscie prototypowe function Base(name){ this.name = name; } //here is an example how to create method that will be //shared across all objects of Base ‘class’ Base.prototype.toString = function(){ return "name:" + this.name; }; var b = new Base("b1"); alert(b.toString()); //displays name:b1 //in fact alert() calls toString() method //and Base.toString() overrides Object.toString() method
Emulacja dziedziczenia klas(c.d.) var b = new Base("b1");
Emulacja dziedziczenia klas (c.d.) //class Derived : Base function Derived(name,count) { Base.call(this,name); //Derived : base(name) this.count = count; } //Derived prototype have to be linked with Base prototype Derived.prototype = new Base(); //yes, Derived has custom toString() implementation Derived.prototype.toString = function() { return "name:"+this.name+",count:"+this.count; }; var d = new Derived("d1",5); alert(d.toString()); //displays name:b1,count:5
Emulacja dziedziczenia klas (c.d.) Derived.prototype = new Base(); var d = new Derived("d1",5);
Prototypy • Nie można emulować prywatnych składowych • Brak duplikacji funkcji – rozmiar obiektu nie zależy od liczby ani rozmiaru funkcji • Główny problem to niekontrolowana zmiana zawertości prototypu -
Domknięcia Funkcje mogą być definiowane wewnątrz innych funkcji Wewnętrzne funkcje mają dostep do zmiennych i parametrów f. zewnętrznej Jesli referencja do wewnętrznej funkcji (callback) istnieje – utrzymywana jest przy życiu f. zewnętrzna function createChecker(treshold) { return function(numberToCheck) { return (numberToCheck > treshold) ? true : false; } } var checker100 = createChecker(100); alert(checker100(99)); //displays false
Emulacja prywatnych właściwości Prywatne właściwości można zaemulować przy użyciu domknięć function Person(name){ //C# readonly this.getName=function() {return name;}; var count; this.getCount=function() {return count;}; this.setCount= function(newCount) { count=newCount;}; this.publicMethod=function(){ alert(this.name); //undefined alert(this.getName()); //ok }
Uwaga na prototypy function Base(){ var count; this.GetCount=function() {return count;}; this.SetCount=function(newCount){count=newCount;}; } function Derived() { Base.call(this); //!!! } Derived.prototype = new Base(); var cd1=new Derived(); var cd2=new Derived(); //cd1.GetCount()==cd2.GetCount() cd1.SetCount(100); //cd1.GetCount()!=cd2.GetCount()
Emulacja namespaces Przestrzenie nazw mogą być emulowane jako var DATA={}; DATA.IO={}; DATA.IO.Parsers={}; var SC = DATA.IO.Parsers; //jak C# using DATA.IO.Class1=function(...){...}; DATA.IO.Class1.prototype.toString=function(){...}; var c1 = new SC.Class1(...);
Dziwactwa Javascript-u voidnie jest typem, to prefiksowy operator zwracajacy zawsze wartość undefined Operatory bitowe i przesuniecia są wspierane ale nie ma wbudowanego typu integer. 64-bitowy typ zmiennoprzecinkowy Numberjest konwerowany na 32-bitowy typ całkowity przed operacją i po niej konwertowany ponownie do Number Operator typeofzwraca string opisujący dany obiekt. typeof(newArray())i typeof(null)zwrócą ”object” (zamiast odpowiednio ”array”i ”null”)
function getLabel() { var count = 0, concatenation = "" ['dog','cow','rabbit'].forEach(function(animal,i){ count = i+1 concatenation += animal + ' ' }) return { 'count' : count, 'animals' : concatenation } }
Javascriptwymagaśredników … więc je sam sobie dodaje Gdy po nowej linii jest błedny token Gdy po nowej linii następuje ++ lub -- Gdy nowa linia następuje po continue, break, return, throw Na koncu pliku – jeśli to potrzebne ale nie dodaje Gdyby to zaowocowało pustą instrukcją Wewnątrz nagłówka instrukcji for
function getLabel() { var count = 0, concatenation = "" ['dog','cow','rabbit'].forEach(function(animal,i){ count = i+1 ; concatenation += animal + ' ' ; }) ; return ; { 'count' : count, 'animals' : concatenation } ; }
function getLabel() { var count = 0, concatenation = "" ['dog','cow','rabbit'].forEach(function(animal,i){ count = i+1 ; concatenation += animal + ' ' ; }) ; return ; { 'count' : count, 'animals' : concatenation } ; }
""['dog','cow','rabbit'] return ; { 'count' : count, 'animals' : concatenation } ; undefined Zwracaundefinefined pomijane
""['dog','cow','rabbit'] return ; { 'count' : count, 'animals' : concatenation } ; Możliwe rozwiazania: Dodajemy wszędzie średniki Dodajemy srednik przed linią która zaczyna się od ‘[‘ ‘(‘ binarnego operatora +- */ Uzywamy JSLinta/JSHinta undefined Zwracaundefinefined pomijane