Descoperiți JavaScript funcțional a fost numit unul dintre cele mai bune cărți noi de programare funcțională de BookAuthority!

JavaScript are elemente primitive, obiecte și funcții. Toate acestea sunt valori. Toate sunt tratate ca obiecte, chiar și primitive.

Primitive

Număr, boolean, șir, undefined și null sunt primitivi.

Număr

Există un singur tip de număr în JavaScript, tipul de virgulă mobilă pe 64 de biți. Aritmetica numerelor zecimale este inexactă.

După cum probabil știți deja, 0.1 + 0.2 nu face 0.3 . Dar cu numerele întregi, aritmetica este exactă, deci 1+2 === 3 .

Numerele moștenesc metode de la Number.prototype obiect. Metodele pot fi apelate pe numere:

(123).toString();  //"123"
(1.23).toFixed(1); //"1.2"

Există funcții pentru convertirea șirurilor în numere: Number.parseInt(), Number.parseFloat() și Number():

Number.parseInt("1")       //1
Number.parseInt("text")    //NaN
Number.parseFloat("1.234") //1.234
Number("1")                //1
Number("1.234")            //1.234

Operațiile aritmetice nevalide sau conversiile nevalide nu vor genera o excepție, dar vor avea ca rezultat NaN Valoarea „Nu este un număr”. Number.isNaN() poate detecta NaN .

+ operatorul poate adăuga sau concatena.

1 + 1      //2
"1" + "1"  //"11"
1 + "1"    //"11"

Şir

Un șir stochează o serie de caractere Unicode. Textul poate fi cuprins între ghilimele duble "" sau ghilimele simple ''.

Șirurile moștenesc metode de la String.prototype. Au metode precum: substring(), indexOf() și concat() .

"text".substring(1,3) //"ex"
"text".indexOf('x')   //2
"text".concat(" end") //"text end"

Corzile, ca toate primitivele, sunt imuabile. De exemplu concat() nu modifică șirul existent, dar creează unul nou.

Boolean

Un boolean are două valori: true și false .
Limbajul are valori adevărate și false.
false, null, undefined, ''(Șir gol), 0 și NaN sunt falsi. Toate celelalte valori, inclusiv toate obiectele, sunt adevărate.

Valoarea adevărată este evaluată la true atunci când este executat într-un context boolean. Valoarea falsului este evaluată la false. Aruncați o privire la următorul exemplu care afișează false ramură.

let text="";
if(text) {
  console.log("This is true");
} else {
  console.log("This is false");
}

Operatorul egalității este ===. Operatorul nu este egal !== .

Variabile

Variabilele pot fi definite folosind var, let și const.

var declară și opțional inițializează o variabilă. Variabile declarate cu var au un scop funcțional. Acestea sunt tratate ca fiind declarate în partea de sus a funcției. Aceasta se numește ridicare variabilă.

let declarația are un domeniu de aplicare bloc.

Valoarea unei variabile care nu este inițializată este undefined .

O variabilă declarată cu const nu poate fi realocat. Cu toate acestea, valoarea sa poate fi încă mutabilă. const blochează variabila, Object.freeze() îngheață obiectul. const declarația are un domeniu de aplicare bloc.

Obiecte

Un obiect este o colecție dinamică de proprietăți.

Cheia de proprietate este un șir unic. Când se utilizează un șir non ca cheie de proprietate, acesta va fi convertit într-un șir. Valoarea proprietății poate fi o primitivă, un obiect sau o funcție.

Cel mai simplu mod de a crea un obiect este să folosiți un obiect literal:

let obj = {
  message : "A message",
  doSomething : function() {}
}

Există două modalități de a accesa proprietăți: notația punct și notația paranteză. Putem citi, adăuga, edita și elimina proprietățile unui obiect în orice moment.

  • obține: object.name, object[expression]
  • a stabilit: object.name = value, object[expression] = value
  • șterge: delete object.name, delete object[expression]
let obj = {}; //create empty object
obj.message = "A message"; //add property
obj.message = "A new message"; //edit property
delete obj.message; //delete property

Obiectele pot fi folosite ca hărți. O hartă simplă poate fi creată folosind Object.create(null) :

let french = Object.create(null);
french["yes"] = "oui";
french["no"]  = "non";
french["yes"];//"oui"

Toate proprietățile obiectului sunt publice. Object.keys() poate fi folosit pentru a itera peste toate proprietățile.

function logProperty(name){
  console.log(name); //property name
  console.log(obj[name]); //property value
}
Object.keys(obj).forEach(logProperty);

Object.assign() copiază toate proprietățile de la un obiect la altul. Un obiect poate fi clonat prin copierea tuturor proprietăților sale într-un obiect gol:

let book = { title: "The good parts" };
let clone = Object.assign({}, book);

Un obiect imuabil este un obiect care odată creat nu poate fi schimbat. Dacă doriți să faceți obiectul imuabil, utilizați Object.freeze() .

Primitive vs obiecte

Primitive (cu excepția null și undefined) sunt tratate ca obiecte, în sensul că au metode, dar nu sunt obiecte.

Numerele, șirurile și booleenii au împachetări echivalente cu obiectele. Acestea sunt Number, String, și Boolean funcții.

Pentru a permite accesul la proprietăți pe primitive, JavaScript creează un obiect wrapper și apoi îl distruge. Procesul de creare și distrugere a obiectelor wrapper este optimizat de motorul JavaScript.

Primitivele sunt imuabile, iar obiectele sunt mutabile.

Matrice

Tablourile sunt colecții indexate de valori. Fiecare valoare este un element. Elementele sunt ordonate și accesate prin numărul lor de index.

JavaScript are obiecte asemănătoare matricei. Tablourile sunt implementate folosind obiecte. Indexurile sunt convertite în șiruri și utilizate ca nume pentru recuperarea valorilor.

O matrice simplă ca let arr = ['A', 'B', 'C'] este emulat folosind un obiect ca cel de mai jos:

{
  '0': 'A',
  '1': 'B',
  '2': 'C'
}

Rețineți că arr[1] dă aceeași valoare ca arr['1'] : arr[1] === arr['1'] .

Eliminarea valorilor din matrice cu delete va lăsa găuri. splice() poate fi folosit pentru a evita problema, dar poate fi lent.

let arr = ['A', 'B', 'C'];
delete arr[1];
console.log(arr); // ['A', empty, 'C']
console.log(arr.length); // 3

Matricile JavaScript nu aruncă excepții de la „index în afara intervalului”. Dacă indexul nu este disponibil, acesta va reveni undefined.

Stiva și coada pot fi ușor implementate folosind metodele matrice:

let stack = [];
stack.push(1);           // [1]
stack.push(2);           // [1, 2]
let last = stack.pop();  // [1]
console.log(last);       // 2

let queue = [];
queue.push(1);           // [1]
queue.push(2);           // [1, 2]
let first = queue.shift();//[2]
console.log(first);      // 1

Funcții

Funcțiile sunt unități de comportament independente.

Funcțiile sunt obiecte. Funcțiile pot fi atribuite variabilelor, stocate în obiecte sau matrice, transmise ca argument altor funcții și returnate din funcții.

Există trei moduri de a defini o funcție:

  • Declarație de funcție (denumită Declarație de funcție)
  • Expresia funcției (aka Funcția literală)
  • Funcția săgeată

Declarația funcțională

  • function este primul cuvânt cheie de pe linie
  • trebuie să aibă un nume
  • poate fi folosit înainte de definire. Declarațiile de funcție sunt mutate sau „ridicate””, până la vârful domeniului lor de aplicare.
function doSomething(){}

Expresia funcției

  • function nu este primul cuvânt cheie de pe linie
  • numele este opțional. Poate exista o expresie de funcție anonimă sau o expresie de funcție numită.
  • trebuie definit, apoi se poate executa
  • se poate executa automat după definiție (numită „IIFE” Expresie de funcție invocată imediat)
let doSomething = function() {}

Funcția săgeată

Funcția săgeată este o sintaxă a zahărului pentru crearea unei expresii funcționale anonime.

let doSomething = () => {};

Funcțiile săgeată nu au propriile lor funcții this și arguments.

Invocarea funcției

O funcție, definită cu function cuvânt cheie, poate fi invocat în diferite moduri:

  • Forma funcției
doSomething(arguments)
  • Forma metodei
theObject.doSomething(arguments)
theObject["doSomething"](arguments)
  • Forma constructorului
new Constructor(arguments)
  • Aplicați formularul
 doSomething.apply(theObject, [arguments])
 doSomething.call(theObject, arguments)

Funcțiile pot fi invocate cu mai multe sau mai puține argumente decât cele declarate în definiție. Argumentele suplimentare vor fi ignorate, iar parametrii lipsă vor fi setați la undefined.

Funcțiile (cu excepția funcțiilor săgeată) au doi pseudo-parametri: this și arguments.

acest

Metodele sunt funcții care sunt stocate în obiecte. Funcțiile sunt independente. Pentru ca o funcție să știe pe ce obiect să lucrezethis este folosit. this reprezintă contextul funcției.

Nu are rost să folosim this când se invocă o funcție cu forma funcției: doSomething(). În acest caz this este undefined sau este window obiect, în funcție de modul strict este activat sau nu.

Când o funcție este invocată cu formularul de metodă theObject.doSomething(),this reprezintă obiectul.

Când o funcție este utilizată ca constructor new Constructor(), thisreprezintă obiectul nou creat.

Valoarea a this poate fi setat cu apply() sau call():doSomething.apply(theObject). În acest caz this este obiectul trimis ca prim parametru metodei.

Valoarea a this depinde de modul în care a fost invocată funcția, nu de locul unde a fost definită funcția. Aceasta este desigur o sursă de confuzie.

argumente

arguments pseudo-parametrul oferă toate argumentele utilizate la invocare. Este un obiect asemănător matricei, dar nu un tablou. Îi lipsesc metodele matrice.

function log(message){
  console.log(message);
}

function logAll(){
  let args = Array.prototype.slice.call(arguments);
  return args.forEach(log);
}

logAll("msg1", "msg2", "msg3");

O alternativă este noua sintaxă a parametrilor de odihnă. De data asta args este un obiect matrice.

function logAll(...args){
  return args.forEach(log);
}

întoarcere

O funcție cu nr return declarația se întoarce undefined. Fiți atenți la inserarea automată a punctelor și virgulelor atunci când utilizați return. Următoarea funcție nu va returna un obiect gol, ci mai degrabă un undefined unu.

function getObject(){ 
  return 
  {
  }
}
getObject()

Pentru a evita problema, utilizați { pe aceeași linie ca return :

function getObject(){ 
  return {
  }
}

Tastare dinamică

JavaScript are tastare dinamică. Valorile au tipuri, variabilele nu. Tipurile se pot modifica în timpul rulării.

function log(value){
  console.log(value);
}

log(1);
log("text");
log({message : "text"});

typeof() operatorul poate verifica tipul unei variabile.

let n = 1;
typeof(n);   //number

let s = "text";
typeof(s);   //string

let fn = function() {};
typeof(fn);  //function

Un singur fir

Principalul timp de rulare JavaScript este cu un singur thread. Două funcții nu pot rula în același timp. Runtime conține o coadă de evenimente care stochează o listă de mesaje care urmează să fie procesate. Nu există condiții de cursă, nu există impasuri. Cu toate acestea, codul din Coada de evenimente trebuie să ruleze rapid. În caz contrar, browserul nu va răspunde și va cere să omoare sarcina.

Excepții

JavaScript are un mecanism de gestionare a excepțiilor. Funcționează așa cum vă așteptați, prin împachetarea codului folosind try/catch afirmație. Declarația are o singură catch bloc care gestionează toate excepțiile.

Este bine de știut că JavaScript are uneori o preferință pentru erorile silentioase. Următorul cod nu va face excepție când încerc să modific un obiect înghețat:

let obj = Object.freeze({});
obj.message = "text";

Modul strict elimină unele erori silențioase JavaScript. "use strict"; activează modul strict.

Modele de prototip

Object.create(), funcția constructor și class construiți obiecte peste sistemul prototip.

Luați în considerare următorul exemplu:

let servicePrototype = {
 doSomething : function() {}
}

let service = Object.create(servicePrototype);
console.log(service.__proto__ === servicePrototype); //true

Object.create() construiește un obiect nou service care areservicePrototype obiect ca prototip al acestuia. Aceasta înseamnă că doSomething() este disponibil pe service obiect. De asemenea, înseamnă că __proto__ proprietatea service indică spre servicePrototype obiect.

Să construim acum un obiect similar folosind class.

class Service {
  doSomething(){}
}

let service = new Service();
console.log(service.__proto__ === Service.prototype);

Toate metodele definite în Service clasa va fi adăugată laService.prototype obiect. Exemple de Service clasa va avea același prototip (Service.prototype) obiect. Toate instanțele vor delega apeluri de metodă către Service.prototype obiect. Metodele sunt definite o datăService.prototype și apoi moștenit de toate cazurile.

Lanț prototip

Obiectele moștenesc de la alte obiecte. Fiecare obiect are un prototip și își moștenește proprietățile de la acesta. Prototipul este disponibil prin proprietatea „ascunsă” __proto__ .

Când solicitați o proprietate pe care obiectul nu o conține, JavaScript va căuta în lanțul prototip până când va găsi proprietatea solicitată sau până când va ajunge la capătul lanțului.

Modele funcționale

JavaScript are funcții și închideri de primă clasă. Acestea sunt concepte care deschid calea programării funcționale în JavaScript. Ca urmare, sunt posibile funcții de ordin superior.

filter(), map(), reduce() sunt setul de instrumente de bază pentru lucrul cu tablouri într-un stil funcțional.

filter() selectează valori dintr-o listă pe baza unei funcții predicate care decide ce valori trebuie păstrate.

map() transformă o listă de valori într-o altă listă de valori utilizând o funcție de mapare.

let numbers = [1,2,3,4,5,6];

function isEven(number){
  return number % 2 === 0;
}

function doubleNumber(x){
  return x*2;
}

let evenNumbers = numbers.filter(isEven);
//2 4 6
let doubleNumbers = numbers.map(doubleNumber);
//2 4 6 8 10 12

reduce() reduce o listă de valori la o valoare.

function addNumber(total, value){
  return total + value;
}

function sum(...args){
  return args.reduce(addNumber, 0);
}

sum(1,2,3); //6

Închiderea este o funcție interioară care are acces la variabilele funcției părinte, chiar și după executarea funcției părinte. Uită-te la următorul exemplu:

function createCount(){
   let state = 0;
   return function count(){
      state += 1;
      return state;
   }
}

let count = createCount();
console.log(count()); //1
console.log(count()); //2

count() este o funcție imbricată. count() accesează variabila state de la părintele său. Supraviețuiește invocării funcției părinte createCount().count() este o închidere.

O funcție de ordin superior este o funcție care ia o altă funcție ca intrare, returnează o funcție sau le face pe ambele.

filter(), map(), reduce() sunt funcții de ordin superior.

O funcție pură este o funcție care returnează o valoare bazată doar pe intrarea sa. Funcțiile pure nu folosesc variabile din funcțiile exterioare. Funcțiile pure nu provoacă mutații.

În exemplele anterioare isEven(), doubleNumber(), addNumber() și sum()sunt funcții pure.

Concluzie

Puterea JavaScript stă în simplitatea sa.

Cunoașterea elementelor fundamentale JavaScript ne ajută să înțelegem și să folosim mai bine limbajul.

Învăța funcțional React, într-un mod bazat pe proiecte, cu Arhitectură funcțională cu React și Redux.

Descoperiți JavaScript funcțional a fost numit unul dintre cele mai bune cărți noi de programare funcțională de BookAuthority!

Pentru mai multe despre aplicarea tehnicilor de programare funcționale în React, aruncați o privire Reactie functionala.

Urmăriți pe Twitter