Featured

CUM SA TESTEZI CODUL JAVASCRIPT?

jasmine

1. Introducere
Jasmine este un framework pentru testarea codului de JavaScript, care nu depinde de nici un alt framework de JavaScript. Contine o sintaxa curata, astfel incat testele pot fi scrise cu usurinta.

2. “Describe
Orice test incepe cu un call la functia Jasmine globala describe care are doi parametrii:

  • un string (numele sau titlu a ceea ce se testeaza);
  • o functie : (un bloc de cod prin care se implementeaza testul propriu-zis);

Acesta functie poate contine mai multe spec-uri.

3. “Specs”
Specificatiile testului sunt definite prin functia Jasmine globala it care are si ea doi parametrii:

  • un string (titlu specificatiilor);
  • o functie (testul);

Un spec (test) contine una sau mai multe “asteptari” care trebuie indeplinite, caz in care testul va fi executat cu succes. Aceste asa zise “asteptari” sunt construite cu functia expect care ia o valoare si apeleaza actuala valoare:

describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

Astfel se verifica daca o anumita parte din cod face exact ceea ce ar trebui sa faca. Daca toate verficarile vor returna un rezultat true atunci testul va fi unul cu succes.

describe("A suite is just a function", function() {
  var x;

  it("and so is a spec", function() {
    x = true;

    expect(x).toBe(true);
  });
});

4. Variabile
Un aspect extrem de important este faptul ca variabilele declarate in describe sunt globale si vor fi accesibile in orice it.

5. “Expect”
Cu ajutorul functie expect se verifica daca o variabila are atribuita valoarea pe care o dorim sau daca o expresie, o functie funtioneaza corect.

6. “Matchers”
Exista numeroare functii pe care le putem folosi pentru a testa daca o valoaare este egala cu alta sau daca este mai mica, mai mare, daca este definita sau nu, sau daca un sir contine un anumit numar etc. Acestia se numesc matchers.

  • toBe
  • not.toBe
describe("Included matchers:", function() {

  it("The 'toBe' matcher compares with ===", function() {
    var x = 1;
    var y = x;

    expect(x).toBe(y);
    expect(x).not.toBe(null);
  });

Se poate observa ca orice matcher poate fi negat punand not la inceput.

  • toEqual
  • not.toEqual
  describe("The 'toEqual' matcher", function() {

    it("works for simple literals and variables", function() {
      var x = 1;
      expect(x).toEqual(1);
    });

    it("should work for objects", function() {
      var obj1 = {
        x: 1,
        y: 3
      };
      var obj2 = {
        x: 1,
        y: 3
      };
      expect(obj1).toEqual(obj2);
    });
  });

Se poate folosi atat pentru variabile cat si pentru obiecte.

  • toMatch
  • not.toMatch
  it("The 'toMatch' matcher is for regular expressions", function() {
    var message = "water milk banana";

    expect(message).toMatch(/milk/);
    expect(message).toMatch("milk");
    expect(message).not.toMatch(/dfx/);
  });

Aici se foloseste pentru a verifica daca respectiva propozitie contine acel cuvantul milk.

  • toBeDefined
  • toBeUndefined
  it("The 'toBeDefined' matcher compares against `undefined`", function() {
    var animal = {
      dog: "dog"
    };

    expect(animal.dog).toBeDefined();
    expect(animal.cat).not.toBeDefined();
  });

  it("The `toBeUndefined` matcher compares against `undefined`", function() {
    var animal = {
      dog: "dog"
    };

    expect(animal.dog).not.toBeUndefined();
    expect(animal.cat).toBeUndefined();
  });
  • toBeNull
  • not.toBeNull
  it("The 'toBeNull' matcher compares against null", function() {
    var x = null;
    var y = "y";

    expect(null).toBeNull();
    expect(x).toBeNull();
    expect(y).not.toBeNull();
  });
  • toBeTruthy
  • not.toBeTruthy
  it("The 'toBeTruthy' matcher is for boolean casting testing", function() {
    var x, y = "y";

    expect(y).toBeTruthy();
    expect(x).not.toBeTruthy();
  });

Se verifica daca o variabila are sau nu valoare, iar in acest caz x este fara valoare.

  • toBeFalsy
  • not.toBeFalsy
  it("The 'toBeFalsy' matcher is for boolean casting testing", function() {
    var x, y = "y";

    expect(x).toBeFalsy();
    expect(y).not.toBeFalsy();
  });
  • toContain
  • not.toContain
  describe("The 'toContain' matcher", function() {
    it("works for finding an item in an Array", function() {
      var a = ["milk", "water", "banana"];

      expect(a).toContain("banana");
      expect(a).not.toContain("uxas");
    });

    it("also works for finding a substring", function() {
      var a = "water banana milk";

      expect(a).toContain("banana");
      expect(a).not.toContain("uxas");
    });
  });
  • toBeLessThan
  it("The 'toBeLessThan' matcher is for mathematical comparisons", function() {
    var a = 3.9,
      b = 2.78;

    expect(b).toBeLessThan(a);
    expect(a).not.toBeLessThan(b);
  });
  • toBeGraterThan
  it("The 'toBeGreaterThan' matcher is for mathematical comparisons", function() {
    var a = 3.9,
      b = 2.78;

    expect(a).toBeGreaterThan(b);
    expect(b).not.toBeGreaterThan(a);
  });
  • toBeCloseTo
  it("The 'toBeCloseTo' matcher is for precision math comparison", function() {
    var pi = 3.1415926,
      e = 2.78;

    expect(pi).not.toBeCloseTo(e, 2);
    expect(pi).toBeCloseTo(e, 0);
  });
  • toThrow
  it("The 'toThrow' matcher is for testing if a function throws an exception", function() {
    var a = function() {
      return 1 + 5;
    };
    var b = function() {
      return a + 5;
    };
    var c = function() {
      throw 'error';
    };

    expect(a).not.toThrow();
    expect(b).toThrow();
    expect(c).toThrow('error');
  });
  • toThrowError
  it("The 'toThrowError' matcher is for testing a specific thrown exception", function() {
    var myFunction = function() {
      throw new TypeError("a b c");
    };

    expect(myFunction).toThrowError("a b c");
    expect(myFunction).toThrowError(/b/);
    expect(myFunction).toThrowError(TypeError);
    expect(myFunction).toThrowError(TypeError, "a b c");
  });
});

7. BeforeEach / AfterEach

Acestea se folosesc pentru a impiedica duplicarea codului. BeforeEach este chemat inaintea fiecarui spec, iar AfterEach dupa fiecare spec.
Variabilele vor fi declarate inainte de BeforeEach.In BeforeEach se asigneaza valori variabilelor deja declarate, iar in AfterEach se reseteaza valorile.

describe("A spec (with setup and tear-down)", function() {
  var a;

  beforeEach(function() {
    a = 0;
    a += 1;
  });

  afterEach(function() {
    a = 0;
  });

  it("is just a function, so it can contain any code", function() {
    expect(a).toEqual(1);
  });

  it("can have more than one expectation", function() {
    expect(a).toEqual(1);
    expect(true).toEqual(true);
  });
});

8. “this

Este un alt mod de a share-ui variabile intre BeforeEach, it si AfterEach. Nu vom mai aveam cuvantul “var”. Foarte important este faptul ca o variabila definita in it nu este accesibila in alt it, insa putem avea describe in describe.

describe("A spec", function() {
  beforeEach(function() {
    this.a = 0;
  });

  it("can use the `this` to share state", function() {
    expect(this.a).toEqual(0);
    this.b = "test";
  });

  it("a variable defined in the last it will not be accessible in this it", function() {
    expect(this.a).toEqual(0);
    expect(this.b).toBe(undefined);
  });
});

9. “xdescribe”

Cu xdescribe un test se anuleaza si nu va mai fi rulat.

10. Pending Specs

Aceste teste nu vor fi rulate (“xit”), dar numele le va aparea la rezultat. Orice spec fara body va aparea la fel.

11. “Spies”

Jasmine are functii de test duble numite “spies”. Un spy exista doar in blocul describe sau it unde este definit si va fi inlaturat dupa fiecare spec. Exista matchers speciali pentru interactiuna cu spies:

  • toHaveBeenCalled (retuneaza true daca spy-ul a fost chemat)
  • toHaveBeenCalledWith (retuneaza true daca spy-ul a fost chemat cu o anumita valoare)
describe("A spy", function() {
  var a, b = null;

  beforeEach(function() {
    a = {
      setValue: function(value) {
        b = value;
      }
    };

    spyOn(a, 'setValue');

    a.setValue(123);
    a.setValue(45, 'another param');
  });

  it("tracks that the spy was called", function() {
    expect(a.setValue).toHaveBeenCalled();
  });

  it("tracks all the arguments of its calls", function() {
    expect(a.setValue).toHaveBeenCalledWith(123);
    expect(a.setValue).toHaveBeenCalledWith(45, 'another param');
  });

  it("stops all execution on a function", function() {
    expect(b).toBeNull();
  });
});
  • and.callThrough

Folosind and.callThrough spy-ul va urmari toate call-urile.

describe("A spy, when configured to call through", function() {
  var a, b, c;

  beforeEach(function() {
    a = {
      setValue: function(value) {
        b = value;
      },
      getValue: function() {
        return b;
      }
    };

    spyOn(a, 'getValue').and.callThrough();

    a.setValue(123);
    c = a.getValue();
  });

  it("tracks that the spy was called", function() {
    expect(a.getValue).toHaveBeenCalled();
  });

  it("should not affect other functions", function() {
    expect(b).toEqual(123);
  });

  it("when called returns the requested value", function() {
    expect(c).toEqual(123);
  });
});
  • and.returnValue

Toate call-urile la functie vor returna o valoare specifica.

describe("A spy, when configured to fake a return value", function() {
  var a, b, c;

  beforeEach(function() {
    a = {
      setValue: function(value) {
        b= value;
      },
      getValue: function() {
        return b;
      }
    };

    spyOn(a, "getValue").and.returnValue(745);

    a.setValue(123);
    c = foo.getValue();
  });

  it("tracks that the spy was called", function() {
    expect(a.getValue).toHaveBeenCalled();
  });

  it("should not affect other functions", function() {
    expect(b).toEqual(123);
  });

  it("when called returns the requested value", function() {
    expect(c).toEqual(745);
  });
});
  • and.callFake
describe("A spy, when configured with an alternate implementation", function() {
  var a, b, c;
  beforeEach(function() {
    a = {
      setValue: function(value) {
        b = value;
      },
      getValue: function() {
        return b;
      }
    };
  spyOn(a, "getValue").and.callFake(function(arguments, can, be, received) {
      return 1001;
    });

    a.setValue(123);
    c = a.getValue();
  });

  it("tracks that the spy was called", function() {
    expect(a.getValue).toHaveBeenCalled();
  });

  it("should not affect other functions", function() {
    expect(b).toEqual(123);
  });

  it("when called returns the requested value", function() {
    expect(c).toEqual(1001);
  });
});
  • and.throwError

Toate call-urile la spy vor arunca o eroare.

describe("A spy, when configured to throw an error", function() {
  var a, b;

  beforeEach(function() {
    a = {
      setValue: function(value) {
        b = value;
      }
    };

    spyOn(a, "setValue").and.throwError("error");
  });

  it("throws the value", function() {
    expect(function() {
      a.setValue(123)
    }).toThrowError("error");
  });
});
  • and.stub

Comportamentul original la stub-ului poate fi retunat oricand se foloseste aceasta comanda.

describe("A spy", function() {
  var a, b = null;

  beforeEach(function() {
    a = {
      setValue: function(value) {
        b = value;
      }
    };

    spyOn(a, 'setValue').and.callThrough();
  });

  it("can call through and then stub in the same spec", function() {
    a.setBar(123);
    expect(b).toEqual(123);

    a.setValue.and.stub();
    b = null;

    a.setValue(123);
    expect(b).toBe(null);
  });
});
  • proprietatea “calls”

Fiecare call la un spy poate fi accesibil folosind proprietatea calls.

describe("A spy", function() {
  var foo, bar = null;

  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      }
    };

    spyOn(foo, 'setBar');
  });
it("tracks if it was called at all", function() {
    expect(foo.setBar.calls.any()).toEqual(false);

    foo.setBar();

    expect(foo.setBar.calls.any()).toEqual(true);
  });
it("tracks the number of times it was called", function() {
    expect(foo.setBar.calls.count()).toEqual(0);

    foo.setBar();
    foo.setBar();

    expect(foo.setBar.calls.count()).toEqual(2);
  });
it("tracks the arguments of each call", function() {
    foo.setBar(123);
    foo.setBar(456, "baz");

    expect(foo.setBar.calls.argsFor(0)).toEqual([123]);
    expect(foo.setBar.calls.argsFor(1)).toEqual([456, "baz"]);
  });
it("tracks the arguments of all calls", function() {
    foo.setBar(123);
    foo.setBar(456, "baz");

    expect(foo.setBar.calls.allArgs()).toEqual([[123],[456, "baz"]]);
  });
it("can provide the context and arguments to all calls", function() {
    foo.setBar(123);

    expect(foo.setBar.calls.all()).toEqual([{object: foo, args: [123]}]);
  });
it("has a shortcut to the most recent call", function() {
    foo.setBar(123);
    foo.setBar(456, "baz");

    expect(foo.setBar.calls.mostRecent()).toEqual({object: foo, args: [456, "baz"]});
  });
it("has a shortcut to the first call", function() {
    foo.setBar(123);
    foo.setBar(456, "baz");

    expect(foo.setBar.calls.first()).toEqual({object: foo, args: [123]});
  });
it("tracks the context", function() {
    var spy = jasmine.createSpy('spy');
    var baz = {
      fn: spy
    };
    var quux = {
      fn: spy
    };
    baz.fn(123);
    quux.fn(456);

    expect(spy.calls.first().object).toBe(baz);
    expect(spy.calls.mostRecent().object).toBe(quux);
  });
it("can be reset", function() {
    foo.setBar(123);
    foo.setBar(456, "baz");

    expect(foo.setBar.calls.any()).toBe(true);

    foo.setBar.calls.reset();

    expect(foo.setBar.calls.any()).toBe(false);
  });
});

If we need to trigger an observableArray mutation when one of its element changes. we can use valueHasMutated() function.

.NET Design Patterns and JavaScript Design Patterns

Design pattern-urile sunt solutii pentru problemele de design care se intalnesc zi de zi in diferite aplicatii.

Acestea se impart in 3 mari cetgorii:

    • Creational
  Abstract Factory Creaza o instanta a mai multor familii de clase
  Builder Separa crearea obiectului de reprezentarea lui
  Factory Method Creaza o instanta a mai multor clase derivate
  Prototype O instanta initializata, copiata si clonata
  Singleton O clasa poate avea o singura instanta
    • Structural
 Adapter Match-uieste interfate de la clase diferite
  Bridge Separa interfata unui obiect de implementare
  Composite O structura de tip “tree” a obiectele simnple si compuse
  Decorator Adauga responsabilitati obiectelor in mod dinamic
  Facade O singura clasa care reprezinta intrugul sistem
  Flyweight O instanta folosita pe sharing eficient
  Proxy Un obiect reprezinta un alt obiect
    • Behavioral
 Chain of Resp. Un mod de a pasa un request intre un lant de obiecte
  Command Incapsuleaza un request ca un obiect
  Interpreter Un mod de a include elemente de limba intr un program
  Iterator Acceseaza secvential elementele unei colectii
  Mediator Defineste comunicarea simplificata intre clase
  Memento Captureaza si recupereaza starea interna a unui obiect
  Observer Un mod de a notifica schimbarea la un numar de clase
  State Altereaza comportamentul unui obiect cand starea lui se schimba
  Strategy Incapsuleaza un algoritm in interiorul unei clase
  Template Method Amana pasii exacti ai unui algoritm la o subclasa
  Visitor Defineste o operatie noua a unei clase fara schimbari

1. Abstract Factory

Definitie= ofera o interfata pentru crearea famililor de obiecte ( dependente sau care au legatura unul cu celalalt) fara a specifica clasele lor concrete.

Diagrama

abstract

Participanti

  • AbstractFactory: declara o interfata pentru operatiile care creaza abstract products
  • ConcreteFactory: implementeaza operatiile pentru a crea product objects
  • AbstractProduct: declara o interfata pt un type of product object
  • Product: defineste un product object si implementeaza AbstractProduct interface
  • Client: foloseste cele 2 interfete

 

Object.create()

  • Object.create() este o metoda statica care creaza un nou obiect cu prototype-ul setat la un obiect anume
const cat={
 makeSound: function() {
  console.log('miau');
  }
}

cat.makeSound(); //miau
const cat={
 makeSound: function() {
  console.log(this.sound);
  }
}

const mark= Object.create(cat);// creaza un nou obiect si va seta prototipul
 acelui obiect sa fie cat
mark.sound= 'miau';

mark.makeSound(); //miau

console.log('Is mark a cat?', cat.isPrototypeOf(mark)); //true

-Object.create() este de preferat pt prototype model in locul new

const cat={
 init: function(sound){
  this.sound= sound
 }
 makeSound: function() {
  console.log(this.sound);
  }
}

function objectCreate(proto) {
  const obj ={}
  Object.setprototypeOf(obj, proto);
  return obj;
}

const mark= objectCreate(cat);// creaza un nou obiect si va seta prototipul
 acelui obiect sa fie cat
mark.init= 'miau';

mark.makeSound(); //miau

console.log('Is mark a cat?', cat.isPrototypeOf(mark)); //true

Concluzii:

-Object.create() este o metoda statica care creaza un nou obiect cu prototype-ul setat la un obiect anume

__proto__ vs prototype

let cat = { breed: 'munchkin'}
let myCat ={ name: 'Sisi'}

Object.setPrototype(myCat, cat);

myCat.name(); // Sisi
myCat.breed();// munchkin
myCat.__proto__ // {breeed: 'munchkin'}, o referinta pt acel obiect

cat.tailLength =15;
myCat.__proto__ // {breeed: 'munchkin', tailLength: 15}
myCat.tailLength //15

– delegarea obiectelor catre alte obiecte

-prototype e pt functii

function Dog(){}

Dog.prototype.breed= 'Bulldog';
let myDog= new Dog();

myDog.breed;// 'Bulldog'

myDog.__proto__ ; // {breed: 'Bulldog'}
myDog.prototype; //undefined
Dog.prototype; // {breed:'Bulldog'} , a fost setat mai sus

function Giraffe() {};
Giraffe.prototype;// {}

let koala= {}
koala.prototype; // undefined
koala.__proto__ ; // {}
koala.__proto__== Object.prototype; //true
Object.prototype.sleep ='zzzzzz';
koala.sleep; //zzzzzz

Concluzii:
__proto__ este proprietatea care pe un obiect, pointeaza catre prototipul care a fost setat

prototype este proprietatea pe o functie, care este setat ca proprietatea daca se foloseste  new

New keyword

  • “new” aplicat functiilor
function Person(saying){
  this.saying= saying;
}

person.prototype.talk = function(){
  console.log('I say:', this.saying);
}

var pers1= new Person('blablabla');

pers1.talk(); //va afisa 'I say:blablabla'

  • creaza un nou obiect,
  • seteaza prototype-ul
  • executa contructorul cu this
  • retuneaza obiectul creat
function Person(saying){
  this.saying= saying;
}

person.prototype.talk = function(){
  console.log('I say:', this.saying);
}

function new1(contructor){
  var obj={};
  Object.setPrototypeOf(obj, contructor.prototype);
  var argsArray= Array.prototype.slice.appaly(arguments);
  constructor.apply(obj, argsArray.slice(1));
  return obj;
}

var pers1= new1(Person,'blablabla');

pers1.talk(); //va afisa 'I say:blablabla'

Daca constructorul retuneaza un obiect:

function Person(saying){
  this.saying= saying;
  return {
   myObj: true
  }
}

person.prototype.talk = function(){
  console.log('I say:', this.saying);
}

function new1(contructor){
  var obj={};
  Object.setPrototypeOf(obj, contructor.prototype);
  var argsArray= Array.prototype.slice.appaly(arguments);
  return constructor.apply(obj, argsArray.slice(1)) || obj;
}

var pers1= new1(Person,'blablabla');
console.log('hello', pers1); //hello {myObj:true}

Concluzii:

new:

  • creaza un nou obiect,
  • seteaza prototype-ul
  • executa contructorul cu this
  • retuneaza obiectul creat

Prototypes

1.Ce sunt prototipurile?

De obicei cand auzim despre mostenire ne gandim la clase. In JavaScript obtinem mostenirea cu prototypes.

Prototipurile si clasele sunt diferite.In viata de zi cu zi un prototip ar putea fi asemanat cu un delegat. O persoana pe care o delegi sa voteze in locul tau atunci cand tu nu esti disponibil.

2. De ce trebuie sa invam despre prototipuri?

Primul motiv ar fi pentru ca este usor de invatat si al doilea motiv ar fi pentru ca in JavaScript exista “class” keyword.

Este un concept mai simplu decat clasele.

Exemplu 1:

function talk(sound){
   console.log(sound);
};

talk('ham'); //va afisa 'ham'

Exemplu 2:

function talk(){
   console.log(this);// this va fi global object, care nu are proprietatea sound
   console.log(this.sound);
};

talk(); //va afisa undefined

Exemplu 3:

function talk(){
   console.log(this);
   console.log(this.sound);
};

let animal = {
    talk:talk;
};

animal.talk(); 
// va afisa {talk: [Function: talk] }, pentru this
// undefined pt ca animal nu are proprietatea sound

Cand apelam animal.talk() tot ce este in stanga la talk va fi vazut ca si this.

Cand asignam unei proprietati o variabila cu acelasi nume, punem sa declaram astfel:

let animal = {
    talk
};

Exemplu 4:

function talk(){
   console.log(this);
   console.log(this.sound);
};

let animal = {
    talk:talk;
};

let cat = {
    sound:'meow'
};

cat.talk();// eroare 'it's not a function' pt ca cat nu are functia talk

Exemplu 5:

function talk(){
   console.log(this);
   console.log(this.sound);
};

let animal = {
    talk:talk;
};

let cat = {
    sound:'meow'
};

Object.setProtoTypeOf(cat, animal);

cat.talk(); 
//{sound: 'meow'} = this
//'meow'

Cum functioneaza? Merge intai in cat si se uita dupa functia talk, nu o gaseste si atunci o cauta in prototip. Are cat prototip? Da are si este animal, care are functia talk.

Exemplu 6:

function talk(){
   console.log(this.sound);
};

let animal = {
    talk:talk;
};

let cat = {
    sound:'meow'
};

let dog = {
    sound:'ham'
};

Object.setProtoTypeOf(cat, animal);
Object.setProtoTypeOf(dog, animal);

cat.talk(); //'meow'

dog.talk(); //'ham'

Exemplu 7:

function talk(){
   console.log(this.sound);
};

let animal = {
    talk:talk;
};

let cat = {
    sound:'meow'
};

let dog = {
    sound:'ham'
};

let bigDog = {
  hamham: function(){
       console.log(this.sound.toUpperCase());
  }
};

Object.setProtoTypeOf(cat, animal);
Object.setProtoTypeOf(dog, animal);

cat.talk(); //'meow'

dog.talk(); //'ham'

bigDog.hamham(); // cannot read property toUpperCase of undefined pt ca
// sound este undefined

Object.setProtoTypeOf(bigDog, dog);
bogDog.hamham();// 'HAM'

Un lucru important este ca prototipurile sunt delegates, ele nu creaza o copie a obiectului original, in acest caz animal. De fapt se delega accesul prototipului la obiectul original. Nu functioneaza ca si clasele care creaza copii.

Exemplu 8:

function talk(){
   console.log(this.sound);
};

let animal = {
    talk:talk;
};
let dog = {
    sound:'ham'
};

let bigDog = {
  hamham: function(){
       console.log(this.sound.toUpperCase());
  }
};

Object.setProtoTypeOf(dog, animal);

animal.talk = function() {
console.log('lalala');
};

Object.setProtoTypeOf(bigDog, dog);

dog.talk(); // va afisa lalala
bigDog.hamham();// va afisa 'HAM'

Desi am setat prototipul pt dog inainte se a asigna alta valoare functie talk, dog.talk() va afisa ‘lalala‘.

Cum functioneaza? Cand se apeleaza dog.talk() se cauta prima data functia talk in dog, nu se gaseste si merge cautarea mai departe in prototip (animal). Acolo gaseste functia talk, dar care a fost schimbata.

Concluzii:

-foloseste pentru acest obiect un alt obiect ca si back-up, ca si prototype;

– daca se apeleaza un obiect cu o proprietate pe care nu o are, cauta proprietatea in celalalt obiect care este prototipul;

-setProtoTypeOf(obj, prototypeObj);

 

Crearea obiectelor in JavaScript

Nu exista o modalitate corecta (sau cea mai corecta) de a crea obiecte in JavaScript.

let dog = {
sound:"ham",
talk: function(){
   console.log(this.sound)
  }
};

dog.talk(); // va afisa "ham"

Avem un obiect “dog”, care are o proprietate “sound”, care are atribuit un string “ham” si metoda “talk”, metoda ce va printa proprietatea. Dupa ce se apeleaza metoda dog.talk() se va afisa “ham”.

let talkFunction= dog.talk;
talkFunction(); // va fi undefined

Am luat metoda “dog.talk” si am reasignat-o unei variabile si apoi am apelat accea variabila.

In JavaScript putem asigna o functie unei variabile, iar acest lucru este posibil pentru ca JavaScript nu este doar un limbaj orientat pe obiecte, este si un limbaj de programare functionala. Functiile sunt values ca si string-urile sau numere, deci pot fi stocate in variabile.

In exemplu, se va afisa “undefined” pt ca de aceasta data “this” nu va mai fi “dog”. Intr-o functie cuvantul “this” nu se refera la contextul unde a fost definita functia, ci se refera la contextul unde functia a fost apelata.

let talkFunction= dog.talk;
let boundFunction=
   talkFunctionn.bind(dog);
boundFunction(); // va afisa "ham"

“Bind” ia functia “talk” si va returna o noua functie care va face bind(dog). In acest caz “bind” forteaza “this” sa fie “dog”.

let button = document.getElementBy('myNiceButton');

button.addEventListener(
'click',
dog.talk
);

Ne folosim de aceasta data de un buton, la care i-am asignat pe eventul de click, metoda “talk”. Cand se va face click pe buton, “this” nu va fi “dog” ci va fi “window object”.

Acest lucru se poate rezolva adaugand “bind”.

button.addEventListener(
'click',
dog.talk.bind(dog)
);

THIS AND BIND

Avem functia talk cu un parametru sound, care va afisa acel parametru. Astfel, cand functia va fi apelata, se va afisa “lalala”.

function talk(sound){
   console.log(sound);
};

talk('lalala'); //va afisa lalala

Acum vom sterge parametrul functiei si in console.log vom incerca sa accesam proprietatea sound cu this:

function talk(){
   console.log(this.sound);
};

talk(); //undefined

Ce este this? In JavaScript cuvantul this inseamna acelasi lucru ca in engleza =>nu inseamna nimic fara a avea un context.(I dont’t like this. This what? => avem nevoie de context).
Daca vom apela functia talk(), se va afisa undefined.

Cand folosim this, trebuie sa cunoastem contextul. In acest caz this= global object, window object, depinde de compilator.

function talk(){
   console.log(this.sound);
};
 let boromir= {
  sound: 'my new sound'
}

let talkBoundToBoromir = talk.bind(boromir);
talkBoundToBoromir(); // va afisa "my new sound"
talk(); //undefined

Cu bind se spune in mod explicit la ce anume ne referim cand spunem this. 

talkBoundToBoromir() va functiona pentru ca este o copie a functiei talk() unde am binduit this la o valoare specifica.

O alta modalitate este sa punem o referinta la functie ca o proprietate. Un lucru foarte important este ca functile in JavaScript sunt doar niste valori, care pot fi atribuite unor proprietati.

let talk = function() {
  console.log(this.sound);
 }; 

let boromir= {
  speak: talk, // o referinta a functie talk a fost asignata la proprietatea speak
  sound: 'my new sound'
};

boromir.speak(); // am apelat proprietatea unui obiect
talk(); // undefined

// asignam unei variabile
let bla = boromir.speak;
bla();// undefined pentru ca bla se refera la acceasi functie

Folosind bind lucrurile se schimba putin:

let talk = function() {
  console.log(this.sound);
 }; 

let boromir= {
    sound: 'my new sound'
};

boromir.speak= talk.bind(boromir);

let bla = boromir.speak;
bla();// va afisa "my new sound" pentru ca a fost bind-uit
talk();// undefined

Un alt exemplu:

let talk = function() {
  console.log(this.sound);
 }; 

let boromir= {
    blabla: talk,
    sound: 'my new sound'
};

let gollum = {
    jabber: boromir.blabla,
    sound: "Happiness....."
};

gollum.jabber();// va afisa "Happiness....."

Concluzii:

-this reprezinta contextul in momentul apelului;

-o functie este doar o valoare;

-o functie poate fi asignata unei proprietati a unui obiect;

-o functie poate fi asignata unei variabile;

-o functie poate fi argumentul unei functii;

-un functie poate fi apelata in contexte multiple;

this are sens cand se cunoaste contextul, altfel se foloseste bind (se creaza o noua functie).

 

 

Cum se mock-uiesc datele?

  • data:

myDate: new Date()

  • un Url

myUrl: “http://myTestURL”

  • un boolean

myBoolean: true

myBoolean: false

  • un string:

myString: “” , daca vrem sa fie gol sau

myString:”test”

  • un array:

myArray: []

  • un obiect:

myObject: {}

  • un array de obiecte:

myArrayOfObjects: [{},{},{}]

  • un observable:

myObservable: ko.observable()

myObservable: ko.observable(true)

myObservable: ko.observable(false)

myObservable: ko.observable(“myString”)

  • un observableArray:

myObservable: ko.observableArray()

  • o functie care nu retuneaza nimic:

myFunction: function () { }

  • o functie care retuneaza un obiect:

myFunction: function () { return {}; }

  • o functie care retuneaza un promise:

myFunction: function() { return $.Deferred().promise(); }

  • un promise:

putPromise: function() {
return $.Deferred().resolve(‘Test’, ‘success’, { status: 200 }).promise();
}

myPromise: $.Deferred().resolve({Items: [], Links: []})

myPromise: function (param) {
var dfr = $.Deferred();
dfr.resolve(param);
return dfr.promise();
}

myPromise: function (param) {
var dfr = $.Deferred();
dfr.resolve(null, [[]]);
return dfr.promise();
}

  • un event

myEvent: ko.event()

  • un spy:

myFunction: jasmine.createSpy()

myFunction: jasmine.createSpy(‘myFunction’)

myFunction: jasmine.createSpy(‘myFunction’).and.callFake(function () {
return $.Deferred().resolve({}, 200, {status: ‘OK’}).promise();
})

myObservable: jasmine.createSpy(‘myObservableSpy’,myObservable).and.callThroug()

  • un ViewModel

myViewModel= new myViewModel()

myViewModel= new myViewModel(param)

  • fake server

myFakeserver: sinon.fakeServer.create();

myFakeServer.respondWith(“GET”, myUrl, JSON.stringify(response));

  • functie ce returneaza un promise

sinon.stub().returns($.Deferred().resolve([]).promise())

sinon.spy(function () { var dfr = $.Deferred(); dfr.resolve(); return dfr.promise(); });

jasmine.createSpy().and.callFake(function() {
return smth;
})

myMethod: sinon.stub().returns(cachedProductListingMock)

myMethod: sinon.stub().returns({})

sinon.spy()