Diferència entre revisions de la pàgina «NF1 - Estructures definides pel Programador - Funcions»

De wikiserver
Dreceres ràpides: navegació, cerca
(Exercicis)
(Exercicis)
 
(211 revisions intermèdies per 4 usuaris que no es mostren)
Línia 1: Línia 1:
 
= Funcions =
 
= Funcions =
 +
http://es6-features.org/
 +
desestructuración.
 +
spread vs rest
  
== Comprovació i Depuració ==
+
https://www.arquitecturajava.com/javascript-closure-funcionamiento/
 +
 
 +
https://cybmeta.com/var-let-y-const-en-javascript
 +
 
 +
== Comprovació i Depuració ==
  
 
Crear conjunts de proves efectius per al codi sempre és important, per això ho tractem ara, abans de continuar amb les funcions.
 
Crear conjunts de proves efectius per al codi sempre és important, per això ho tractem ara, abans de continuar amb les funcions.
Línia 70: Línia 77:
 
web: http://qunitjs.com/
 
web: http://qunitjs.com/
 
===== Exemple d'ús: =====
 
===== Exemple d'ús: =====
Primer creem un còpia del codi a testar. Per exemple creem el fitxer exercici5.js on tenim la solució del exercici 5 de la unitat anterior. L'exercici consisteix a posar al revés un text donat.
 
  
 +
 +
'''EJEMPLO 1'''
 
<source lang="javascript">
 
<source lang="javascript">
/*Contingut del fitxer exercici5.js */
+
 
 +
<html>
 +
  <head>
 +
      <meta charset = "utf-8">
 +
      <title>QUnit basic example</title>
 +
      <link rel = "stylesheet" href = "https://code.jquery.com/qunit/qunit-1.22.0.css">
 +
      <script src = "https://code.jquery.com/qunit/qunit-1.22.0.js"></script>
 +
  </head>
 +
 
 +
  <body>
 +
      <div id = "qunit"></div>
 +
      <div id = "qunit-fixture"></div>
 +
     
 +
      <script>
 +
        function square(x) {
 +
            return x * x;
 +
        }
 +
        QUnit.test( "TestSquare", function( assert ) {
 +
            var result = square(2);
 +
            assert.equal( result, "4", "square(2) should be 4." );
 +
        });
 +
      </script>
 +
  </body>
 +
</html>
 +
 
 +
</source>
 +
 
 +
 
 +
'''EJERCICIO '''
 +
 
 +
Se desea hacer un test de pruebas con la función ponerAlRevés, por ello deberá ponerse valores negativos, positivos, float, palabra... y las cadenas con alguna coma, mayúscula.
 +
 
 +
 
 +
 
 +
 
 +
<source lang ="javascript">
 
function posarReves(opcio, text) {
 
function posarReves(opcio, text) {
 
var separator = " ";
 
var separator = " ";
Línia 81: Línia 124:
 
return text.split(separator).reverse().join(separator);
 
return text.split(separator).reverse().join(separator);
 
}
 
}
 +
</source>
  
</source>
 
  
Segon creem un joc de proves per aquest exercici. Per exemple podem crear un fitxer anomenat jocProvesEx5.js
+
<!--
El contingut del fitxer pot ser el següent:
+
'''SOLUCIÓ:'''
  
 
<source lang="javascript">
 
<source lang="javascript">
test("Conjunt de Tests", function() {
+
<html>
equal(posarReves("333", "hola a tots"), false);
+
  <head>
equal(posarReves("huksi", "hola a tots"), false);
+
      <meta charset = "utf-8">
equal(posarReves(-2, "hola a tots"), false);
+
      <title>QUnit basic example</title>
equal(posarReves(0, "hola, a tots"), "stot a ,aloh");
+
      <link rel = "stylesheet" href = "https://code.jquery.com/qunit/qunit-1.22.0.css">
equal(posarReves(0, "hola a tots"), "stot a aloh");
+
      <script src = "https://code.jquery.com/qunit/qunit-1.22.0.js"></script>
equal(posarReves("dead", "hola a tots"), false);
+
  </head>
equal(posarReves(1, "hola, a tots"), "tots a hola,");
+
 
equal(posarReves(1, "hola a tots"), "tots a hola");
+
  <body>
 +
      <div id = "qunit"></div>
 +
      <div id = "qunit-fixture"></div>
 +
     
 +
      <script>
 +
       
 +
/*Contingut del fitxer exercici5.js */
 +
function posarReves(opcio, text) {
 +
var separator = " ";
 +
if(opcio == 0){
 +
separator = "";
 +
}
 +
return text.split(separator).reverse().join(separator);
 +
}
 +
 
 +
 
 +
 
 +
QUnit.test("Conjunt de Tests", function(assert) {
 +
assert.equal(posarReves("333", "hola a tots"), "tots a hola", "Se espera -> 'tots a hola'");
 +
assert.equal(posarReves("huksi", "hola a tots"), "tots a hola", "Se espera -> 'tots a hola'");
 +
assert.equal(posarReves(-2, "hola a tots"), "tots a hola", "Se espera -> 'tots a hola'");
 +
assert.equal(posarReves(0, "hola, a tots"), "tots a hola", "Se espera -> 'stot a ,aloh'");
 +
assert.equal(posarReves(1, "hola, a tots"), "tots a hola", "Se espera -> 'tots a hola'");
 
});
 
});
 +
 +
 +
 +
      </script>
 +
  </body>
 +
</html>
 
</source>
 
</source>
  
Tercer creem el HTML on combinem el codi a provar, els tests i les llibreries de QUnit.
+
-->
 +
 
 +
 
 +
<!--
 +
Primer creem un còpia del codi a testar. Per exemple creem el fitxer exercici5.js on tenim la solució del exercici 5 de la unitat anterior. L'exercici consisteix a posar al revés un text donat.
 +
 
 +
<source lang="javascript">
 +
/*Contingut del fitxer exercici5.js */
 +
function posarReves(opcio, text) {
 +
var separator = " ";
 +
if(opcio == 0){
 +
separator = "";
 +
}
 +
return text.split(separator).reverse().join(separator);
 +
}
  
<source lang="javascript">
 
<!DOCTYPE html>
 
<html>
 
<head>
 
<meta http-equiv="Content-Type" content="text/html" charset=utf-8" />
 
<title>Tests per al exercici 5</title>
 
<link href="qunit-1.15.0.css" type="text/css" rel="stylesheet" />
 
<script src="qunit-1.15.0.js"></script>
 
<script src="jocProvesEx5.js"></script>
 
<script src="exercici5.js"></script>
 
</head>
 
<body>
 
<div id="qunit"></div>
 
</body>
 
</html>
 
 
</source>
 
</source>
  
Gràcies a aquest conjunt de proves podem veure que ens fa falta una funció de detecció d'errors més acurada sobre la variable ''opcio''.
+
Segon creem un joc de proves per aquest exercici. Per exemple podem crear un fitxer anomenat jocProvesEx5.js
 +
El contingut del fitxer pot ser el següent:
  
==== YUI Test ====
+
<source lang="javascript">
És un entorn de comprovació creat per Yahoo! Proporciona un nombre impressionant de característiques i funcionalitats que garanteixen la cobertura de qualsevol cas de comprovació única. Es distingeix per:
+
test("Conjunt de Tests", function() {
*Àmplia i exhaustiva funcionalitat
+
equal(posarReves("333", "hola a tots"), false);
*És compatible amb la comprovació asincrónica
+
equal(posarReves("huksi", "hola a tots"), false);
*Bona simulació d'esdeveniments.
+
equal(posarReves(-2, "hola a tots"), false);
web : http://yuilibrary.com/projects/yuitest/
+
equal(posarReves(0, "hola, a tots"), "stot a ,aloh");
 +
equal(posarReves(0, "hola a tots"), "stot a aloh");
 +
equal(posarReves("dead", "hola a tots"), false);
 +
equal(posarReves(1, "hola, a tots"), "tots a hola,");
 +
equal(posarReves(1, "hola a tots"), "tots a hola");
 +
});
 +
</source>
  
==== JsUnit ====
+
Tercer creem el HTML on combinem el codi a provar, els tests i les llibreries de QUnit.
És el més antic en termes d'edat de la base de codi i qualitat. Ve del popular entorn de comprovació Java JUnit per Javascript. L'entorn no s'ha actualitzat molt recentment i per això pot ser que no sigui la millor opció per treballar amb els navegadors moderns.
 
web: https://github.com/pivotal/jsunit
 
Existeix una versió que s'està implementant per donar suport als nous navegadors que es diu Jasmine:
 
web: https://github.com/pivotal/jasmine
 
  
=== Exercicis ===
+
<source lang="javascript">
 +
<!DOCTYPE html>
 +
<html>
 +
<head>
 +
<meta http-equiv="Content-Type" content="text/html" charset=utf-8" />
 +
<title>Tests per al exercici 5</title>
 +
<link href="qunit-1.15.0.css" type="text/css" rel="stylesheet" />
 +
<script src="qunit-1.15.0.js"></script>
 +
<script src="jocProvesEx5.js"></script>
 +
<script src="exercici5.js"></script>
 +
</head>
 +
<body>
 +
<div id="qunit"></div>
 +
</body>
 +
</html>
 +
</source>
  
==== Exercici 1 ====
+
Gràcies a aquest conjunt de proves podem veure que ens fa falta una funció de detecció d'errors més acurada sobre la variable ''opcio''.
Crea un joc de proves per al Exercici 3 DNI. Canvia els alerts de comprovació, si tens, per console.log(). Utilitza el framework QUnit.
+
-->
  
==== Exercici 2 ====
+
==== JEST ====
Crea un joc de proves per al Exercici 7 Nombres Romans.Canvia els alerts de comprovació, si tens, per console.log(). Utilitza el framework QUnit.
 
  
==== Exercici 3 ====
+
==== YUI Test ====
Unifica els dos jocs de proves anteriors en un mateix fitxer. Es a dir, només has de tindre els següents fitxers: Fitxer HTML, Fitxer qunit-1.12.0.css, Fitxer qunit-1.12.0.js, Fitxer JocProvesUnificat.js, Fitxer Exercicis.js
+
És un entorn de comprovació creat per Yahoo! Proporciona un nombre impressionant de característiques i funcionalitats que garanteixen la cobertura de qualsevol cas de comprovació única. Es distingeix per:
 +
*Àmplia i exhaustiva funcionalitat
 +
*És compatible amb la comprovació asincrónica
 +
*Bona simulació d'esdeveniments.
 +
web : http://yuilibrary.com/projects/yuitest/
 +
 
 +
==== JsUnit ====
 +
És el més antic en termes d'edat de la base de codi i qualitat. Ve del popular entorn de comprovació Java JUnit per Javascript. L'entorn no s'ha actualitzat molt recentment i per això pot ser que no sigui la millor opció per treballar amb els navegadors moderns.
 +
web: https://github.com/pivotal/jsunit
 +
Existeix una versió que s'està implementant per donar suport als nous navegadors que es diu Jasmine:
 +
web: https://github.com/pivotal/jasmine
 +
 
 +
<!-- comentat per Mónica
 +
=== Exercicis ===
 +
 
 +
==== Exercici 1 ====
 +
Crea un joc de proves per al Exercici 3 DNI. Canvia els alerts de comprovació, si tens, per console.log(). Utilitza el framework QUnit.
 +
 
 +
==== Exercici 2 ====
 +
Crea un joc de proves per al Exercici 7 Nombres Romans.Canvia els alerts de comprovació, si tens, per console.log(). Utilitza el framework QUnit.
 +
 
 +
==== Exercici 3 ====
 +
Unifica els dos jocs de proves anteriors en un mateix fitxer. Es a dir, només has de tindre els següents fitxers: Fitxer HTML, Fitxer qunit-1.12.0.css, Fitxer qunit-1.12.0.js, Fitxer JocProvesUnificat.js, Fitxer Exercicis.js
 +
-->
  
 
== Les Funcions son fonamentals ==
 
== Les Funcions son fonamentals ==
Línia 150: Línia 260:
 
La funció és la principal unitat modular d'execució. Vol dir que excepte els comandos incrustats en el codi que s'executen mentre es avalua les etiquetes, tot la resta de les nostres pàgines està dins d'una funció.
 
La funció és la principal unitat modular d'execució. Vol dir que excepte els comandos incrustats en el codi que s'executen mentre es avalua les etiquetes, tot la resta de les nostres pàgines està dins d'una funció.
  
=== Les funcions com a objectes de primera classe ===
+
 
Els objectes tenen les següents capacitats:
+
=== Objectes ===
* Es creen a través de literals.
+
 
 +
La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta :
 +
<source lang="java">
 +
var obj1 = new Object();
 +
var obj2 = {};
 +
</source>
 +
 
 +
Això crea un objecte nou, buit i que més tard podem ampliar amb propietats:
 +
<source lang="java">
 +
var o = {};
 +
o.name = "Marta";
 +
o.feina = "contable";
 +
o.antiguitat = 11;
 +
</source>
 +
 
 +
Per eliminar una propietat podem utilitzar l'operador ''delete'':
 +
<source lang="java">
 +
var obj1 = new Object()
 +
alert(obj1.nombre)  // undefined
 +
 
 +
obj1.nombre = "mundo"
 +
alert(obj1.nombre)  // "mundo"
 +
 
 +
delete obj1.nombre
 +
 
 +
alert(obj1.nombre)  // undefined otra vez
 +
</source>
 +
 
 +
Per afegir un mètode podem fer:
 +
<source lang="java">
 +
var obj1 = new Object();
 +
obj1.nombre = "mundo";
 +
obj1.saluda = function() { alert("hola "+this.nombre) };
 +
obj1.saluda();
 +
</source>
 +
 
 +
També podem construir objectes de manera literal:
 +
<source lang="java">
 +
var obj1 = {nombre:"mundo",
 +
            saluda: function() { alert("hola "+this.nombre) }
 +
};
 +
obj1.saluda();
 +
</source>
 +
 
 +
I podem accedir als mètodes i a les propietats de diferents maneres:
 +
<source lang="java">
 +
var obj1 = new Object();
 +
obj1.nombre = "mundo";
 +
obj1.saluda = function() { alert("hola "+this.nombre) };
 +
 
 +
alert("hola " + obj1.nombre);      // Acceso normal
 +
alert("hola " + obj1[ "nombre" ]);  // Acceso indexado con un literal
 +
var prop = "nombre";
 +
alert("hola " + obj1[ prop ]);      // Acceso indexado con una variable
 +
 
 +
obj1.saluda();        // Invocación normal
 +
obj1[ "saluda" ]();    // Acceso indexado con un literal
 +
var func = "saluda";
 +
obj1[ func ]();        // Acceso indexado con una variable
 +
</source>
 +
 
 +
=== Les funcions com a objectes de primera classe ===
 +
Els objectes tenen les següents capacitats:
 +
* Es creen a través de literals.
 
* S'assignen a variables, entrades de matriu i propietats d'altres objectes.
 
* S'assignen a variables, entrades de matriu i propietats d'altres objectes.
 
* Es poden passar com a arguments per a funcions.
 
* Es poden passar com a arguments per a funcions.
Línia 175: Línia 348:
 
</source>
 
</source>
  
=== Declaracions ===
+
<!--=== Declaracions ===
 
Les funcions es declaren usant una funció literal que crea un valor de la mateixa manera que un literal numèric. Les funcions són valors que poden emprar-se en el llenguatge igual que altres valors, com les cadenes o els nombres. Les funcions literals es componen de quatre parts:
 
Les funcions es declaren usant una funció literal que crea un valor de la mateixa manera que un literal numèric. Les funcions són valors que poden emprar-se en el llenguatge igual que altres valors, com les cadenes o els nombres. Les funcions literals es componen de quatre parts:
 
*1. La paraula clau ''function''
 
*1. La paraula clau ''function''
Línia 214: Línia 387:
 
Joc de proves:
 
Joc de proves:
 
<source lang="javascript">
 
<source lang="javascript">
 +
 +
//qunit
 
test("Conjunt de Tests per a funcions", function() {
 
test("Conjunt de Tests per a funcions", function() {
 
equal(typeof window.lleugera === "function", true);
 
equal(typeof window.lleugera === "function", true);
Línia 225: Línia 400:
 
equal(window.una_funcio.name === "una_altre_funcio", true);
 
equal(window.una_funcio.name === "una_altre_funcio", true);
 
});
 
});
 +
 +
 +
//Mediante Consola
 +
console.log(typeof window.lleugera === "function"); //true
 +
console.log(lleugera.name === "lleugera"); //true
 +
console.log(lleugera.name === "lleugera"); //true
 +
console.log(typeof window.sensenom === "function"); //true
 +
console.log(sensenom.name === "");  //false
 +
console.log(typeof window.esVeritat === "function"); //true
 +
console.log(typeof window.externa === "function"); //true
 +
console.log(typeof window.interna === "function"); //false
 +
console.log(window.una_funcio.name === "una_altre_funcio"); //true
 
</source>
 
</source>
  
Línia 237: Línia 424:
 
Ara que ja sabem definir funcions crea el teu propi framework. El nucli d'un entorn de comprovació única es el seu mètode conegut com a ''assert()''. Aquest rep dos paràmetres, un valor i una descripció. Si el valor s'avalua com a cert, la assert s'avalua com a correcte. Si es fals, llavors l'assert s'avalua com a fallada.
 
Ara que ja sabem definir funcions crea el teu propi framework. El nucli d'un entorn de comprovació única es el seu mètode conegut com a ''assert()''. Aquest rep dos paràmetres, un valor i una descripció. Si el valor s'avalua com a cert, la assert s'avalua com a correcte. Si es fals, llavors l'assert s'avalua com a fallada.
  
<!--:[[solucio framework tests unitaris]]-->
+
:[[solucio framework tests unitaris]]
 +
 
 +
-->
 +
 
 +
=== Arrow => ===
  
=== Àmbit de les variables ===
 
  
L'àmbit d'una variable (anomenat "scope" en anglès) és la zona del programa en la qual es defineix la variable. JavaScript defineix dos àmbits per a les variables: global i local.
 
  
El següent exemple il·lustra el comportament dels àmbits:
+
¿Cuántas veces has programado un código con una estructura similar a la siguiente?
  
 
<source lang="javascript">
 
<source lang="javascript">
function creaMensaje () {
+
// ES5
var missatge = "Missatge de prova";
+
// Imaginemos una variable data que incluye un array de objectos
}  
+
var data = [{'nombre':"julio","apellido":"noguera"}, {"nombre":"albert","apellido":"canela"}, {"nombre":"alex","apellido":"salinas"}];
creaMensaje ();
 
alert (missatge);
 
  
</source>
+
data.forEach(function(i){
   
+
  console.log(i);
L'exemple anterior defineix en primer lloc una funció anomenada creaMensaje que cregui una variable anomenada missatge. A continuació, s'executa la funció mitjançant l'anomenada creaMensaje (); i tot seguit, es mostra mitjançant la funció alert () el valor de una variable anomenada missatge.
 
  
No obstant això, en executar el codi anterior ''no mostra cap missatge per pantalla''.
+
});
La raó és que la variable missatge s'ha definit dins de la funció creaMensaje () i per tant, és una variable local que només està definida dins de la funció.
 
  
Qualsevol instrucció que es trobi dins de la funció pot fer ús d'aquesta variable, però totes les instruccions que es trobin en altres funcions o fora de qualsevol funció no tindran definida la variable missatge. D'aquesta manera, per mostrar el missatge en el codi anterior, la funció alert () ha de cridar des de dins de la funció creaMensaje ():  
+
</source>
 +
Con la función arrow => de ES6, el código anterior se sustituiría por:
  
 
<source lang="javascript">
 
<source lang="javascript">
function creaMensaje () {
+
//ES6
var missatge = "Missatge de prova";  
+
var data = [{'nombre':"julio","apellido":"noguera"}, {"nombre":"albert","apellido":"canela"}, {"nombre":"alex","apellido":"salinas"}];
alert (missatge);
 
}
 
</source>
 
  
Què passa si una funció defineix una variable local amb el mateix nom que una variable global que ja existeix?
+
data.forEach(i => console.log(i));
En aquest cas, les variables locals prevalen sobre les globals, però només dins de la funció:  
+
 
 +
});
 +
 
 +
</source>
 +
Mucho más limpio y claro. CoffeeScript (un metalenguaje que compila a JavaScript) usa algo parecido.
 +
 
 +
Incluso la podemos utilizar así:
  
 
<source lang="javascript">
 
<source lang="javascript">
var missatge = "guanya la de fora";  
+
// ES5
 +
var miFuncion = function(num) {
 +
return num + num;
 +
}
  
function muestraMensaje () {
+
// ES6
var missatge = "guanya la de dins";
+
var miFuncion = (num) => num + num;
alert (missatge);  
 
}
 
  
alert (missatge);
 
muestraMensaje ();
 
alert (missatge);
 
 
</source>
 
</source>
  
El codi anterior mostra per pantalla els següents missatges:  
+
<h3><span class="mw-headline" id="El_m.C3.A8tode_.map.28.29">El mètode .map()</span></h3>
<source lang="es">
+
<p>La funció <b>map()</b> s'aplica a tots els elements del vector, de maneta similar a <i>forEach()</i>:  
guanya la de fora
+
</p>
guanya la de dins
+
 
guanya la de fora
+
<source lang="javascript">
 +
let noms= ['julio', 'albert', 'alex'];
 +
noms.map(i=> i.length);
 +
})
 
</source>
 
</source>
  
Dins de la funció, la variable local anomenada missatge té més prioritat que la variable global del mateix nom, però només dins de la funció.
+
 
Què passa si dins d'una funció es defineix una variable global amb el mateix nom que una altra variable global que ja existeix? En aquest altre cas, la variable global definida dins de la funció simplement modifica el valor de la variable global definida anteriorment:
+
Altre exemple
  
 
<source lang="javascript">
 
<source lang="javascript">
var missatge = "guanya la de fora";  
+
var vect = [1,2,3,4,5];
 
+
vect.map(function(i){
function muestraMensaje () {
+
return i+5;
missatge = "guanya la de dins";
+
})
alert (missatge);  
 
}  
 
 
 
alert (missatge);
 
muestraMensaje ();
 
alert (missatge);
 
 
</source>
 
</source>
  
En aquest cas, els missatges mostrats són:  
+
<p>que retorna: [ 6, 7, 8, 9, 10 ]
 
+
</p><p>El vector inicial no es modifica, ie, <b>map()</b> no és destructiva. Si imprimim el vector de nou:
<source lang="es">
+
</p>
guanya la de fora
+
<source lang="javascript">
guanya la de dins
+
vect
guanya la de dins
+
[ 1, 2, 3, 4, 5 ]
 
</source>
 
</source>
  
La recomanació general és definir com a variables locals totes les variables que siguin d'ús exclusiu per a realitzar les tasques encomanades a cada funció. les variables globals s'utilitzen per compartir variables entre funcions de forma senzilla.
 
  
 +
<p>Per tant, no podem modificar el vector directament amb coses com:
 +
</p>
  
<!--
+
<source lang="javascript">
=== Àmbit de les funcions ===
+
var vect = [1,2,3,4,5];
 +
vect.map(function(i){
 +
i=i+5;
 +
})
 +
</source>
  
En Javascript els àmbits actuen de forma una mica diferent que en la majoria de llenguatges, la sintaxi dels quals està influenciada per C. En concret, els que utilitzen { i } com a delimitadors de bloc. En la majoria d'aquests llenguatges, cada bloc crea el seu propi àmbit. Això no ocorre amb Javascript.
+
<p>que retorna:
 +
</p>
  
En javascript, les funcions són les que declaren els àmbits i no els blocs. L'àmbit d'una declaració creada dins d'un bloc no acaba (com ocorre en altres llenguatges) al final del bloc.
+
<source lang="javascript">
 +
[ undefined, undefined, undefined, undefined, undefined ]
 +
vect
 +
[ 1, 2, 3, 4, 5 ]
 +
</source>
 +
<p>Però sí podem modificar el vector inicial si li assignem el retorn del mapeig:
 +
</p>
  
Exemple:
+
<source lang="javascript">
 +
var vect = [1,2,3,4,5];
 +
vect = vect.map(function(i){
 +
return i+5;
 +
})
  
 +
/*
 +
var vect = [1,2,3,4,5];
 +
vect = vect.map( i =>  i+5);
 +
*/
 +
</source>
 +
<p>que retorna:
 +
</p>
 
<source lang="javascript">
 
<source lang="javascript">
if(window){
+
[ 6, 7, 8, 9, 10 ]
var x = 213;
 
}
 
alert(x);
 
 
</source>
 
</source>
 +
<p>però ara <b>vect</b> val:
 +
</p>
 +
<pre>[ 6, 7, 8, 9, 10 ]
 +
</pre>
 +
 +
<h3>El mètode .reduce()</span></h3>
 +
<p>És una funció de reducció que s'aplica a tots els elements del vector, però de dos en dos (o més). Exemple:
 +
</p>
 +
 +
<source lang="javascript">
 +
 +
var vect = [1,2,3,4,5];
  
En la majoria de llenguatges esperem que l'àmbit de la declaració de x acabi al final del bloc creat per la sentència ''if'' i que l'alerta falli en un valor no definit.
+
vect.reduce(function(acumulador,incremento){
Però no ocorre així. El valor del alert és 213 perquè javascript no acaba els àmbits al final dels blocs.
+
console.log(acumulador+" "+incremento+" "+(acumulador+incremento));
 +
return acumulador+incremento;
 +
})
 +
</source>
  
Regles per establir un àmbit:
+
<p>que retorna la suma de tots els elements:
 +
</p>
 +
<pre>15
 +
</pre>
  
* 1. Les declaracions de variables estan en l'àmbit des del punt de declaració fins al final de la funció en la qual es declaren, amb independència de la incorporació del bloc
+
'''Exercici'''
  
* 2. Les funcions amb nom estan en l'àmbit de tota la funció en la qual es declaren, amb independència de la incorporació del bloc.
+
Els arrays en Javascript no tenen un mètode que ens retorni el màxim. Usa el mètode reduce per a obtenir el màxim d'un array de nombres.
  
* 3. Per als àmbits de declaració, el context global actua com una gran funció que inclou el codi de la pàgina.
+
Solució:
-->
 
  
==== Exercici 5 ====
 
Observa el següent codi i respon:
 
 
<source lang="javascript">
 
<source lang="javascript">
 +
var vect = [3,25,99,16,80,12,20];
  
function externa(){
+
var major=vect.reduce((a,b)=>{if(a<b) return b;else return a;});
var a = 1;
+
 
 +
document.write("<br>"+typeof major+" "+ major);
 +
</source>
 +
 
 +
'''El mètode .filter()'''
 +
<p>És una funció que s'aplica a tots els elements del vector, i només retorna aquells que compleixen la condició. Exemple:
 +
</p>
  
function interna(){ /* no fa res */ }
+
<source lang="javascript">
+
var vect = [1,2,3,4,5];
var b = 2;
+
var resul=vect.filter(function(i){
if(a ==1 ) {
+
if(i>3)
var c = 3;
+
  return i;
}
+
})
}
 
externa();
 
  
</source>
+
let resul=posts.filter(i=>i>3);  //en resul un array de los números mayores de 3
Quin és l'àmbit de (digues on comença i on acaba):
 
* externa
 
* a
 
* interna
 
* b
 
* c
 
<!--:[[solucio ambits de la funcio]]-->
 
  
==== Exercici 6 ====
+
/*const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
  
Utilitza el teu framework per comprovar l'exercici anterior. Comprova els àmbits de totes les variables i funcions en llocs estratègics del codi
+
const result = words.filter(word => word.length > 6);
 +
//devuelve Array ["exuberant", "destruction", "present"]
  
<!--:[[solucio ambits amb test unitaris]]-->
 
  
=== Invocacions ===
+
*/
Hi ha quatre maneres diferents per invocar a una funció, cadascuna amb les seves peculiaritats.
+
</source>
* 1. Com una '''funció''', en la qual aquesta s'invoca de manera senzilla.
 
* 2. Com un '''mètode''', que vincula la invocació a un objecte, habilitant la programació orientada a objectes.
 
* 3. Com un '''constructor''', en el qual un nou objecte es fa realitat.
 
* 4. A través dels seus '''mètodes ''apply()'' o bé ''call()'' '''
 
  
<u>Dels arguments als paràmetres de les funcions</u>
+
<p>que retorna:
 +
</p>
 +
<pre>resul=[ 4, 5 ]
 +
</pre>
  
Si el nombre d'arguments i paràmetres és diferent, no hi ha error:
+
==== Exercici filter ====
* Si hi ha mes arguments que paràmetres, els arguments de sobres no s'assignen als noms de paràmetres.
 
  
 +
Crea un programa que a partir d'un array de 10 números, obtingui dos arrays anomenats parells i senars amb els números parells i senars respectivament de l'array inicial. Usa el mètode filter.
 +
 +
'''map, arrow,filter, reduce, findIndex'''
 +
 +
Dado un objeto 
 
<source lang="javascript">
 
<source lang="javascript">
function qualsevol(a,b,c){}
+
posts = [
qualsevol(1,2,3,4,5,6); //4,5,6 no s'assignen a cap paràmetre.
+
  {id: 1, upVotes: 2},
 +
  {id: 2, upVotes: 18},
 +
  {id: 3, upVotes: 1},  
 +
  {id: 4, upVotes: 30},  
 +
  {id: 5, upVotes: 50}
 +
];
 
</source>
 
</source>
 +
Se desea hacer un benchmark para comprobar la velocidad de " for, foreach, map, filter, reduce..." por tanto se usará console.time('ejemplo') para establecer el tiempo de inicio y console.timeEnd('ejemplo') para finalizar el cronómetro.
  
* Si hi ha mes paràmetres que arguments, els paràmetres que no tinguin el seu argument corresponent s'estableixen com ''undefined''
+
<!-- Comentat per Mónica
 +
'''Ejercicio test de pruebas'''
 +
'''Solució'''
  
 
<source lang="javascript">
 
<source lang="javascript">
function qualsevol(a,b,c){}
+
const posts = [
qualsevol(1); //b,c tenen el valor undefined
+
{id: 1, upVotes: 2},
 +
{id: 2, upVotes: 18},
 +
{id: 3, upVotes: 1},
 +
{id: 4, upVotes: 30},
 +
{id: 5, upVotes: 50}
 +
];
 +
let sum = 0;
 +
console.time('reduce');
 +
 
 +
sum = posts.reduce((s, p)=> s+=p.upVotes,0);
 +
console.timeEnd('reduce');
 +
 
 +
sum = 0;
 +
console.time('for loop');
 +
 +
for(let i=0; i<posts.length; i++) {
 +
sum += posts[i].upVotes;
 +
}
 +
console.timeEnd('for loop');
 +
 +
sum = 0;
 +
console.time('for each');
 +
posts.forEach(element => {
 +
    sum += element.upVotes;
 +
});
 +
console.timeEnd('for each');
 
</source>
 
</source>
  
En totes les invocacions de les funcions es passen 2 paràmetres implícits (es passen en silenci i estan en el seu àmbit) : arguments i this.
 
* '''Arguments'''
 
Arguments és una col·lecció de tots els arguments que s'han passat a la funció. Té una propietat length que conté el numero de paràmetres que s'han passat. Els valors dels paràmetres es pot obtenir com en un array. Exemple: arguments[2] ens dóna el tercer paràmetre.
 
  
* '''This'''
+
https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7
És el context de la funció. En JAVA this és la instància de la classe en la qual es defineix el mètode. En Javascript no et confiïs.
+
https://medium.com/@joomiguelcunha/learn-map-filter-and-reduce-in-javascript-ea59009593c4
El paràmetre this no es defineix, com en Java, per com es declara la funció, sinó per com s'invoca.
+
-->
  
==== Invocació com una funció ====
+
=== Plantillas literales ===
És la manera ''normal'' d'invocar a una funció en qualsevol llenguatge.
 
Exemple:
 
  
 
<source lang="javascript">
 
<source lang="javascript">
function cridam(){};
 
cridam();
 
var unaltre = function(){};
 
unaltre();
 
</source>
 
  
Quan ho fem d'aquesta manera el contexte de la funció és el global. Aixó vol dir que la funció és una propietat del objecte ''window''. Però donem per implícit aquest objecte en la seva crida.
+
let a = 5;
Realment, aquesta manera és la mateixa que la invocació com a mètode, ja que aquestes funcions són mètodes de l'objecte ''window''.
+
let b = 10;
==== Invocació com un mètode ====
+
 
Es produeix quan s'assigna una funció a la propietat d'un objecte.
+
console.log('Quince es ' + (a + b) + ' y\nno ' + (2 * a + b) + '.');
Exemple:
+
 
 +
// "Quince es 15 y
 +
// no 20.
 +
</source>
  
 
<source lang="javascript">
 
<source lang="javascript">
//es crea l'objecte anomenat 'o'
+
let a = 5;
var o = {};
+
let b = 10;
o.nom_metode = funtion(){};
+
 
//es defineix una propietat anomenada 'nom_metode' i se li assigna una funció.
+
console.log(`Quince es ${a + b} y
//aquesta propietat la hem convertit en un mètode.
+
no ${2 * a + b}.`);
  
o.nom_metode(); //crida al mètode.
+
// "Quince es 15 y
 +
// no 20."
 
</source>
 
</source>
  
Quan invoquem d'aquesta manera a la funció, l'objecte es converteix en el contexte de la funció, es a dir, el paràmetre implícit '''this''' correspon al objecte.
 
  
 +
=== Àmbit de les variables ===
  
'''Què és exactament this'''
+
L'àmbit d'una variable (anomenat "scope" en anglès) és la zona del programa en la qual es defineix la variable. JavaScript defineix dos àmbits per a les variables: global i local.
  
La paraula clau this té en Javascript un comportament diferent al d'altres llenguatges però en general, <u>el seu valor fa referència al propietari de la funció que l'està invocant o, si no, a fi on aquesta funció és un mètode.</u>
+
El següent exemple il·lustra el comportament dels àmbits:
  
La paraula clau del paràgraf anterior és "propietari".
+
<source lang="javascript">
 +
function creaMensaje () {
 +
var missatge = "Missatge de prova";
 +
}
 +
creaMensaje ();
 +
alert (missatge);
  
Quan no estem dins d'una estructura definida, això és un objecte amb mètodes, el propietari d'una funció és sempre el context global. En el cas dels navegadors web, hem de recordar que aquest objecte és window:
+
</source>
 +
 +
L'exemple anterior defineix en primer lloc una funció anomenada creaMensaje que cregui una variable anomenada missatge. A continuació, s'executa la funció mitjançant l'anomenada creaMensaje (); i tot seguit, es mostra mitjançant la funció alert () el valor de una variable anomenada missatge.
 +
 
 +
No obstant això, en executar el codi anterior ''no mostra cap missatge per pantalla''.
 +
La raó és que la variable missatge s'ha definit dins de la funció creaMensaje () i per tant, és una variable local que només està definida dins de la funció.
 +
 
 +
Qualsevol instrucció que es trobi dins de la funció pot fer ús d'aquesta variable, però totes les instruccions que es trobin en altres funcions o fora de qualsevol funció no tindran definida la variable missatge. D'aquesta manera, per mostrar el missatge en el codi anterior, la funció alert () ha de cridar des de dins de la funció creaMensaje ():  
  
<source lang="java">
+
<source lang="javascript">
console.log( this === window );  // true
+
function creaMensaje () {
+
var missatge = "Missatge de prova";
function test(){
+
alert (missatge);
  console.log( this === window);
 
 
}
 
}
 
test(); // true
 
 
</source>
 
</source>
  
 +
Què passa si una funció defineix una variable local amb el mateix nom que una variable global que ja existeix?
 +
En aquest cas, les variables locals prevalen sobre les globals, però només dins de la funció:
  
 +
<source lang="javascript">
 +
var missatge = "guanya la de fora";
  
'''Accedint als valors d'un objecte des del propi objecte'''
+
function muestraMensaje () {
 
+
var missatge = "guanya la de dins";
Aquest concepte de propietari pot induir a errors. Pensem en un objecte amb una sèrie de propietats:
+
alert (missatge);
 +
}
  
<source lang="java">
+
alert (missatge);  
var myApp = {
+
muestraMensaje ();  
  name : 'Megan',
+
alert (missatge);  
  lastName : 'Fox',
 
  birthDate : '16/05/1986',
 
  isPretty : true
 
};
 
 
console.log( myApp.name ); // Megan
 
console.log( myApp.isPretty ); // true
 
 
</source>
 
</source>
  
Suposem ara que necessitem una altra propietat més 'dinàmica' que participi dels valors assignats a qualsevol altra. Per exemple, volem un 'completeName "que concatene' name 'i' lastname '. Sembla que aquest un clar exemple d'ús per a this:
+
El codi anterior mostra per pantalla els següents missatges:  
 +
<source lang="es">
 +
guanya la de fora
 +
guanya la de dins
 +
guanya la de fora
 +
</source>
  
 +
Dins de la funció, la variable local anomenada missatge té més prioritat que la variable global del mateix nom, però només dins de la funció.
 +
Què passa si dins d'una funció es defineix una variable global amb el mateix nom que una altra variable global que ja existeix? En aquest altre cas, la variable global definida dins de la funció simplement modifica el valor de la variable global definida anteriorment:
  
<source lang="java">
+
<source lang="javascript">
var myApp = {
+
var missatge = "guanya la de fora";
  name : 'Megan',
+
 
  lastName : 'Fox',
+
function muestraMensaje () {
  completeName : this.name + this.lastName
+
missatge = "guanya la de dins";
}
+
alert (missatge);
 +
}
 +
 
 +
alert (missatge);
 +
muestraMensaje ();
 +
alert (missatge);
 
</source>
 
</source>
  
Encara que sembla coherent, quan passem a comprovar-ho veiem que el resultat no és l'esperat:  
+
En aquest cas, els missatges mostrats són:  
  
<source lang="java">
+
<source lang="es">
console.log (myApp.completeName); // undefined
+
guanya la de fora
 +
guanya la de dins
 +
guanya la de dins
 
</source>
 
</source>
  
El problema aquí és que dins d'aquest no està apuntant a l'objecte com es podria esperar, sinó que està buscant la referència fora, en el context global (finestra).  
+
La recomanació general és definir com a variables locals totes les variables que siguin d'ús exclusiu per a realitzar les tasques encomanades a cada funció. les variables globals s'utilitzen per compartir variables entre funcions de forma senzilla.
  
Per obtenir el resultat esperat hem d'aplicar un patró d'invocació que modifiqui al propietari des del qual s'invoca el this ...
+
Més exemples
 +
<source lang="java">
  
 +
//Global- Podemos accedes a ellas desde cualquier parte del cogido
 +
//Local - Variables creadas dentro de una función solo pueden ser accedidas, desde su función o una función anidada
  
 +
var variableGlobal = "variable Global";
  
 +
      var miFuncion = function () {
 +
      var variableLocal = "variable Local";
  
'''Patró d'invocació per mètode'''
+
      var funcionLocal = function () {
 +
      var variableLocal = "esta variable es local, dentro de funcionLocal";
 +
      alert(variableLocal);
 +
 
 +
      };
  
 +
      funcionLocal();
  
 +
      alert(variableLocal);  //variable Local
 +
      }
  
En el desenvolupament d'aplicacions modernes, el patró més recurrent és el d'invocació per mètode: una funció és emmagatzemada com a propietat d'un objecte convertint-se així en el que anomenem un mètode.
+
      miFuncion();
  
Quan diem (invoquem) a un mètode, this fa refencia al mateix objecte:
+
      alert(variableLocal);  //falla
  
<source lang="java">
 
var myApp = {
 
  name : 'Megan',
 
  lastName : 'Fox',
 
  completeName : function(){
 
    return this.name + ' ' + this.lastName;
 
  }
 
}
 
 
console.log( myApp.completeName() ); // Megan Fox
 
 
</source>
 
</source>
  
 +
<!--=== Àmbit de les funcions ===
  
En aquesta ocasió, si podem comprovar com this apunta al mateix objecte i busca la propietats 'name' i 'lastname' dins en lloc de remuntar-se fins el context global.
+
En Javascript els àmbits actuen de forma una mica diferent que en la majoria de llenguatges, la sintaxi dels quals està influenciada per C. En concret, els que utilitzen { i } com a delimitadors de bloc. En la majoria d'aquests llenguatges, cada bloc crea el seu propi àmbit. Això no ocorre amb Javascript.
  
===== Exercici 7 =====
+
En javascript, les funcions són les que declaren els àmbits i no els blocs. L'àmbit d'una declaració creada dins d'un bloc no acaba (com ocorre en altres llenguatges) al final del bloc.
  
¿Quin és el seu valor?
+
Exemple:
  
 
<source lang="javascript">
 
<source lang="javascript">
var myApp = function(){
+
if(window){
  var name = "World"
+
var x = 213;
  var sayHello = function(){
+
}
    console.log( 'Hello, ' + this.name );
+
alert(x);
  };
 
  sayHello();  
 
};
 
 
myApp();  
 
 
</source>
 
</source>
  
 +
En la majoria de llenguatges esperem que l'àmbit de la declaració de x acabi al final del bloc creat per la sentència ''if'' i que l'alerta falli en un valor no definit.
 +
Però no ocorre així. El valor del alert és 213 perquè javascript no acaba els àmbits al final dels blocs.
  
Aquest comportament el podem comprovar si creem una variable global amb aquell nom pel qual estem preguntant
+
Regles per establir un àmbit:
¿Quin és el seu valor?
 
  
<source lang="javascript">
+
* 1. Les declaracions de variables estan en l'àmbit des del punt de declaració fins al final de la funció en la qual es declaren, amb independència de la incorporació del bloc
var name = "Strange World";     
 
var myApp = function(){
 
  var name = "World"           
 
  var sayHello = function(){
 
    console.log( 'Hello, ' + this.name );     
 
  };
 
 
  sayHello();
 
 
};
 
 
myApp();
 
  
</source>
+
* 2. Les funcions amb nom estan en l'àmbit de tota la funció en la qual es declaren, amb independència de la incorporació del bloc.
  
La conseqüència d'aquest error és que un mètode no pot utilitzar funcions internes que l'ajudin a fer la seva feina perquè aquestes, no té accés a les seves propietats.
+
* 3. Per als àmbits de declaració, el context global actua com una gran funció que inclou el codi de la pàgina.
  
:[[Solucio this]]
 
 
===== Exercici 7.1 =====
 
Mostra amb un framework unitari qui és l'objecte del argument this en cada cas:
 
  
 +
==== Exercici 5 ====
 +
Observa el següent codi i respon:
 
<source lang="javascript">
 
<source lang="javascript">
function unica(){return this;};
 
  
var replica = unica;
+
function externa(){
 +
var a = 1;
  
var objecte1 = {
+
function interna(){ /* no fa res */ }
clon : unica
+
 +
var b = 2;
 +
if(a ==1 ) {
 +
var c = 3;
 +
}
 
}
 
}
 +
externa();
  
var objecte2 = {
 
clon : unica
 
}
 
 
</source>
 
</source>
 +
Quin és l'àmbit de (digues on comença i on acaba):
 +
* externa
 +
* a
 +
* interna
 +
* b
 +
* c
  
:[[solucio funcio com a metode]]
+
:[[solucio ambits de la funcio]]
 
 
S'ha d'observar que el contexte canvia depenent de com s'invoca la funció. Pensa que la funció és la mateixa en tots els casos. Objecte1 i Objecte2 comparteixen la mateixa instància de la funció, fins i tot quan s'executa, la funció té accés al objecte que va invocar el mètode i pot realitzar operacions amb ell. Aquest és el principi de la programació orientada a objectes.
 
  
===== Exercici 8 =====
+
==== Exercici 6 ====
  
<source lang="java">
+
Utilitza el teu framework per comprovar l'exercici anterior. Comprova els àmbits de totes les variables i funcions en llocs estratègics del codi
var persona = {
 
    name: 'edu',
 
    twitter: 'eiximenis',
 
    twitterUrl: 'http://twitter.com/' + this.twitter
 
};
 
 
console.log(persona.twitterUrl);
 
  
</source>
+
:[[solucio ambits amb test unitaris]]-->
  
 +
<!-- Comentat per Mónica
 +
http://www.webimes.es/blog/ambito-variables-javascript/
 +
-->
  
'''Exercici 8.1'''
+
== Var vs Let ==
  
 +
'''JAVA'''
 
<source lang="java">
 
<source lang="java">
 +
public static void main(String[] args) {
 +
    int a = 1;
 +
    int b = 2;
 +
   
 +
    {
 +
        int c = 3;
 +
    }
  
console.debug(this);
+
    System.out.println(a +" "+ b +" "+ c);
 +
    // Error de compilación: c cannot be resolved to a variable
 +
}
  
function test(){
 
 
console.debug(this);
 
}
 
  
test();
 
 
</source>
 
</source>
  
'''Exercici 8.2'''
 
  
 +
'''JAVASCRIPT'''
 
<source lang="java">
 
<source lang="java">
var obj = {
+
var a = 1;
name: 'obj',
+
var b = 2;
run: function(){
+
 
+
{
this.value = 1;
+
    var c = 3;
console.debug(this.name);
+
}
}
+
 
};
+
console.info(a, b, c); // 1 2 3
 +
 
 +
</source>
 +
 
 +
 
 +
'''LET'''
 +
<source lang="javascript">
 +
 
 +
let a = 1;
 +
let b = 2;
 +
 
 +
{
 +
    let c = 3;
 +
}
 +
 
 +
console.info(a, b, c); // ReferenceError: c is not defined
 +
 
  
obj.run();
 
 
</source>
 
</source>
 +
-----------------
 +
'''VAR'''
 +
 +
En resumen, en ES5 (Javascript más tradicional) no se permitía declarar un alcance más acotado, como las llaves de una condición if, un bucle etc.
 +
 +
'''var''' permite declarar una variable que sea accesible por todos los lugares de la función donde ha sido declarada. Si una variable con var se declara fuera de cualquier función, el ámbito de esta son todas las funciones del código.
  
'''Exercici 8.3'''
+
Veamos un ejemplo:
  
 
<source lang="java">
 
<source lang="java">
var obj = {
+
function miFuncion() {
name: 'obj',
+
 
run: function(){
+
  console.log(miVar);   //undefined
this.value = 1;
+
  if (true) {
console.debug(this);  
+
    var miVar = "Hola mundo";
+
  }
(function(){ // se crea un nuevo scope
+
  console.log(miVar); //Hola mundo
console.debug(this);  
 
})();
 
 
function test(){ // se crea un nuevo scope
 
console.debug(this);
 
}
 
 
test();
 
}
 
 
};
 
};
 +
</source>
  
obj.run();
+
En este caso, pensando en ES5, la variable "miVar" está definida dentro de un bloque if, pero aun así su ámbito será el de la función miFuncion().
</source>
+
 
 +
'''LET'''
 +
 
 +
Para solucionar todo esto en Javascript ES6 se ha implementado alguna forma nueva de declarar variables que ahora será la más indicada en la mayoría de los casos.
  
 +
'''let''' permite declarar una variable que sea accesible únicamente dentro del bloque donde se ha declarado (llamamos bloque al espacio delimitado por { })
  
'''Exercici 8.4'''
+
Se trata de la construcción "let" que veremos mejor con un ejemplo similar:
  
 
<source lang="java">
 
<source lang="java">
var obj = {
+
function () {
    name: 'obj',
+
  console.log(miVar);   //undefined
    run: function(){
+
  if (true) {
        this.value = 1;
+
    let miVar = "Hola mundo";
        console.debug(this);  
+
  }
       
+
  console.log(miVar);   //undefined
        (function(){
+
};
            console.debug(this);  
+
</source>
        }).call(this); // se autoejecuta con el método call
+
 
       
+
La clave de let es que restringe su existencia al ámbito donde ha sido declarada (cualquier ámbito expresado con unas llaves).
        this.test = function(){  
+
 
            console.debug(this);  
+
'''VARIABLES SIN DECLARAR'''
         }
+
 
       
+
Javascript nos permite usar variables no declaradas. Si hacemos esto, será equivalente a declararlas con var fuera del código, es decir, serán variables accesibles por cualquier función.
         this.test();  
+
 
 +
<source lang="javascript">
 +
    function ejemplo() {
 +
      ejemplo = 3; // Equivale a declararla fuera de la funcion como var
 +
      if (ejemplo === 3) {
 +
        var variable1 = 1;
 +
         let variable2 = 2;
 +
      }
 +
 
 +
         console.log(variable1); // variable1 existe en este lugar
 +
    // console.log(variable2); // variable2 no existe en este lugar
 
     }
 
     }
};
 
 
obj.run();
 
  
</source>
+
    ejemplo();
  
:[[solucio exercicis this]]
+
    console.log(ejemplo);
  
==== Invocació com constructor ====
+
</source>
Per invocar una funció com a constructor no té cap misteri. S'ha de posar la paraula ''new'' davant de la funció.
+
 
El que té de interessant és el que passa quan ho fem:
+
=== Invocacions ===
* Es crea un objecte buit.
+
Hi ha quatre maneres diferents per invocar a una funció, cadascuna amb les seves peculiaritats.
* Aquest objecte es passa al constructor com paràmetre ''this'' i d'aquesta manera es converteix en el contexte de la funció.
+
* 1. Com una '''funció''', en la qual aquesta s'invoca de manera senzilla.
* En absència de qualsevol valor retornat de forma explícita, el nou objecte es retorna com a valor del constructor.
+
* 2. Com un '''mètode''', que vincula la invocació a un objecte, habilitant la programació orientada a objectes.
 +
* 3. Com un '''constructor''', en el qual un nou objecte es fa realitat.
 +
* 4. A través dels seus '''mètodes ''apply()'' o bé ''call()'' '''
  
Que passaria si invoquem a la funció sense utilitzar la paraula ''new''?
+
<u>Dels arguments als paràmetres de les funcions</u>
* doncs que no es crea l'objecte i, llavors, les propietats i mètodes que pugui haver pertanyen al objecte ''window''.
 
  
Com sabem si una funció s'utilitza per crear objectes o son funcions normals?
+
Si el nombre d'arguments i paràmetres és diferent, no hi ha error:
* Doncs no hi ha una manera estàndard
+
* Si hi ha mes arguments que paràmetres, els arguments de sobres no s'assignen als noms de paràmetres.
* Per convenció si les funcions creen objectes llavors el nom de la funció comença amb lletra MAJÚSCULA.
 
  
 
<source lang="javascript">
 
<source lang="javascript">
function Cotxe(){
+
function qualsevol(a,b,c){}
this.matricula = "";
+
qualsevol(1,2,3,4,5,6); //4,5,6 no s'assignen a cap paràmetre.
}
 
 
 
/*cridem a la funció d'aquesta manera:*/
 
var cotxe1 = new Cotxe();
 
 
</source>
 
</source>
  
En  aquest exemple, la propietat ''matricula'' pertany a l'objecte ''cotxe1''. Si no haguéssim posat la paraula ''new'' el paràmetre ''this'' que s'utilitza dintre de la funció faria referència al objecte ''window''. Com s'ha posat la paraula ''new'' el paràmetre this fa referència al nou objecte creat.
+
* Si hi ha mes paràmetres que arguments, els paràmetres que no tinguin el seu argument corresponent s'estableixen com ''undefined''
 +
 
 +
<source lang="javascript">
 +
function qualsevol(a,b,c){}
 +
qualsevol(1); //b,c tenen el valor undefined
 +
</source>
  
==== Invocació amb els mètodes apply() i call() ====
+
En totes les invocacions de les funcions es passen 2 paràmetres implícits (es passen en silenci i estan en el seu àmbit) : arguments i this.
 +
* '''Arguments'''
 +
Arguments és una col·lecció de tots els arguments que s'han passat a la funció. Té una propietat length que conté el numero de paràmetres que s'han passat. Els valors dels paràmetres es pot obtenir com en un array. Exemple: arguments[2] ens dóna el tercer paràmetre.
  
Javascript ens proporciona un mitjà per invocar a una funció i especificar de forma explícita qualsevol objecte que vulguem com a context. És a dir, podem decidir quin és el valor del paràmetre ''this'' quan cridem a una funció.
+
* '''This'''
S'aconsegueix amb qualsevol dels dos mètodes que posseeixen les funcions: ''apply()'' i ''call()''.
+
És el context de la funció. En JAVA this és la instància de la classe en la qual es defineix el mètode. En Javascript no et confiïs.
Sí, totes les funciones tenen dos mètodes disponibles, ja que son objectes de primera classe poden tindre propietats i mètodes igual que qualsevol altre objecte.
+
El paràmetre this no es defineix, com en Java, per com es declara la funció, sinó per com s'invoca.
Paràmetres del mètode apply():
 
* L'objecte que s'utilitzarà com a context de la funció
 
* Array de valors que s'utilitzaran com a arguments de la funció.
 
Paràmetres del mètode call():
 
* L'objecte que s'utilitzarà com a context de la funció
 
* Llistat de valors que s'utilitzaran com a arguments de la funció.
 
  
 +
==== Invocació com una funció ====
 +
És la manera ''normal'' d'invocar a una funció en qualsevol llenguatge.
 
Exemple:
 
Exemple:
 +
 
<source lang="javascript">
 
<source lang="javascript">
function exemple(){
+
function cridam(){};
  var result = 0;
+
cridam();
  for (var i = 0; i < arguments.length; i++){
+
var unaltre = function(){};
        result += arguments[i];
+
unaltre();
  }
+
</source>
 
 
  this.result = result;
 
}
 
  
var objecte1 = {};
+
Quan ho fem d'aquesta manera el contexte de la funció és el global. Aixó vol dir que la funció és una propietat del objecte ''window''. Però donem per implícit aquest objecte en la seva crida.
var objecte2 = {};
+
Realment, aquesta manera és la mateixa que la invocació com a mètode, ja que aquestes funcions són mètodes de l'objecte ''window''.
 +
==== Invocació com un mètode ====
  
exemple.apply(objecte1,[1,2,3,4]);
+
http://www.etnassoft.com/2012/01/12/el-valor-de-this-en-javascript-como-manejarlo-correctamente/
exemple.call(objecte2,5,6,7,8);
 
  
// en aquest punt objecte1.result tindrà el valor 10
+
Es produeix quan s'assigna una funció a la propietat d'un objecte.
// i objecte2.result tindrà el valor 26
+
Exemple:
</source>
 
 
 
==== Exercici 9 ====
 
  
Digues que es mostrarà a cada alert. Explica-ho.
 
 
<source lang="javascript">
 
<source lang="javascript">
var missatge2 = "hola"
+
//es crea l'objecte anomenat 'o'
 +
var o = {};
 +
o.nom_metode = funtion(){};
 +
//es defineix una propietat anomenada 'nom_metode' i se li assigna una funció.
 +
//aquesta propietat la hem convertit en un mètode.
  
function Nova (){
+
o.nom_metode(); //crida al mètode.
var missatge2 = "adeu";
 
this.missatge2 = "hello";
 
alert("Missatge2 local: " + missatge2 + " ; Missatge2 global: " + this.missatge2);
 
}
 
 
 
var e = new Nova();
 
alert(e.missatge2);
 
alert("window : " + missatge2);
 
 
</source>
 
</source>
  
== Les funcions sense nom ==
+
Quan invoquem d'aquesta manera a la funció, l'objecte es converteix en el contexte de la funció, es a dir, el paràmetre implícit '''this''' correspon al objecte.
  
Les funcions sense nom s'utilitzen quan volem utilitzar-les posteriorment. Exemples:
 
* quan les emmagatzemem en una variable,
 
* quan les posem com a mètodes d'objectes
 
* quan les utilitzem com devolució de trucada (callback de timeout, callback de controladors d'events, etc).
 
  
<source lang="javascript">
+
'''Què és exactament this'''
window.onload = function () {assert(true, "2");};
 
  
 +
La paraula clau this té en Javascript un comportament diferent al d'altres llenguatges però en general, <u>el seu valor fa referència al propietari de la funció que l'està invocant.</u>
  
var obj = {
+
La paraula clau del paràgraf anterior és "propietari".  
            print : function () {assert(true, "1");}
 
          }
 
obj.print();
 
  
 +
Quan no estem dins d'una estructura definida, això és un objecte amb mètodes, el propietari d'una funció és sempre el context global. En el cas dels navegadors web, hem de recordar que aquest objecte és window:
  
setTimeout(function(){ assert(true, "3"); }, 500);
+
<source lang="java">
 +
console.log( this === window );  // true
 +
 +
function test(){
 +
  console.log( this === window);
 +
}
 +
 +
test(); // true
 
</source>
 
</source>
L'ordre de sortida per pantalla és el següent : 1,2,3
 
També podíem haber fet el següent amb el controlador de l'event càrrega de pàgina:
 
<source lang="javascript">
 
function bootMeUp(){
 
    assert(true, "2");
 
};
 
  
window.onload = bootMeUp;
 
</source>
 
Però, per qué donar-li nom si mai més la cridarem? Realment necessitem que bootMeUp sigui un mètode del objecte window?
 
A més a més, podem pensar que el mètode ''print'' és el nom de la funció anónima que l'assignem. NO!!. Demostra-ho utilitzant la propietat ''name'' de les funcions.
 
  
'''Funcions amb noms en linia'''
 
  
Però que succeeix si posem nom a les funcions sense nom?
+
'''Accedint als valors d'un objecte des del propi objecte'''
Exemple:
+
 
<source lang="javascript">
+
Aquest concepte de propietari pot induir a errors. Pensem en un objecte amb una sèrie de propietats:
var persona = {
+
 
  cantar : function xiular(n){...}
+
<source lang="java">
}
+
var myApp = {
</source>
+
  name : 'Megan',
La funció ''xiular'' no la podem cridar fora de la funció. Peró sí la podem crear dintre, es a dir, ens interesa posar nom a les funcions sense nom quan les volem fer recursives.
+
  lastName : 'Fox',
<source lang="javascript">
+
  birthDate : '16/05/1986',
var persona = {
+
  isPretty : true
  cantar : function xiular(n){ return n > 1 ? xiular(n-1) + "-fiu" : "fiu"; }
+
};
}
+
 +
console.log( myApp.name ); // Megan
 +
console.log( myApp.isPretty ); // true
 
</source>
 
</source>
  
<!-- == Memoritzar valors calculats a la propia funció (Memoize) ==
+
Suposem ara que necessitem una altra propietat més 'dinàmica' que participi dels valors assignats a qualsevol altra. Per exemple, volem un 'completeName "que concatene' name 'i' lastname '. Sembla que aquest un clar exemple d'ús per a this:
 +
 
  
La memorització (memoizacion) és el pas de crear una funció que pot recordar els seus valors calculats amb anterioritat. Així es pot incrementar considerablement el rendiment evitant càlculs complexes innecessaris que ja s'han calculat.
+
<source lang="java">
Exemple: Volem saber si un nombre és un nombre primer:
+
var myApp = {
<pre>
+
  name : 'Megan',
function esPrimer(valor){
+
  lastName : 'Fox',
if(!esPrimer.cache) esPrimer.cache = {};
+
  completeName : this.name + this.lastName
if(esPrimer.cache[valor] != null) {
 
return esPrimer.cache[valor];
 
}
 
var primer = valor != 1 // 1 no pot ser mai primer
 
for(var i = 2; i < valor; i++){
 
if(valor % i == 0){
 
primer = false;
 
break;
 
}
 
}
 
return esPrimer.cache[valor] = primer;
 
 
}
 
}
esPrimer(5);
+
</source>
</pre>
 
-->
 
  
== Sobrecàrrega de funcions ==
+
Encara que sembla coherent, quan passem a comprovar-ho veiem que el resultat no és l'esperat:
  
En altres llenguatges de programació orientats a objectes, per sobrecarregar una funció se sol declarar distintes implementacions de mètodes amb el mateix nombre però amb un conjunt diferent de paràmetres. En Javascript no es fa d'aquesta manera. En Javascript es sobrecarreguen les funcions amb una única implementació que modifica el seu comportament mitjançant l'exàmen del nombre d'arguments que l'han proporcionat.
+
<source lang="java">
 +
console.log (myApp.completeName); // undefined
 +
</source>
 +
 
 +
El problema aquí és que dins d'aquest no està apuntant a l'objecte com es podria esperar, sinó que està buscant la referència fora, en el context global (finestra).  
  
És fàcil d'imaginar que es podria implementar la sobrecàrrega de funcions utilitzant una estructura del tipus if-then i else-if. Però no sempre ho podrem fer.  
+
Per obtenir el resultat esperat hem d'aplicar un patró d'invocació que modifiqui al propietari des del qual s'invoca el this ...
  
Exemple: Funciò sobrecarregada de manera monolítica:
 
<pre>
 
var persona = {
 
        calculMatricula = function(){
 
  switch(arguments.length){
 
case 0:
 
// fer algo
 
break;
 
case 1:
 
// fer una altre cosa
 
break;
 
case 2:
 
// fer una altre cosa més
 
break;
 
... etc ...
 
}
 
}
 
}
 
</pre>
 
Veurem una tècnica per ens permet crear diverses funcions (aparentment amb el mateix nom, però es diferència pel número de paràmetres) que poden escriure's com diferents, anónimes e independents i no com un bloc monolític if-then-else-if.
 
Tot aixó depén de una propietat poc coneguda de les funcions : la propietat length.
 
  
=== length de funció ===
 
  
El paràmetre ''length'' de funció no ha de confondre's amb la propietat ''length'' del paràmetre arguments.
 
El paràmetre ''length'' de funció ens indica el número total de paràmetres formals amb els que s'ha declarat la funció.
 
La propietat ''length'' del paràmetre ''arguments'' ens indica el número total de parámetres que s'han passat a la funció en el moment de cridar-la.
 
  
Exemple:
+
'''Patró d'invocació per mètode'''
<source lang="java">
+
 
function max(a,b){
 
  ...
 
}
 
  
max(1,4,5,7,23,234);
 
  
</source>
+
En el desenvolupament d'aplicacions modernes, el patró més recurrent és el d'invocació per mètode: una funció és emmagatzemada com a propietat d'un objecte convertint-se així en el que anomenem un mètode.
En aquest cas el paràmetre length de la funció max és 2 i la propietat length del paràmetre arguments és 6.
 
  
Utilitzarem aquest paràmetre per crear funcions sobrecarregades.
+
Quan diem (invoquem) a un mètode, this fa refencia al mateix objecte:
  
 
<source lang="java">
 
<source lang="java">
function afegirMetode(objecte, nom, funcio){
+
var myApp = {
var old = objecte[nom];
+
  name : 'Megan',
objecte[nom] = function(){
+
  lastName : 'Fox',
if(funcio.length == arguments.length)
+
  completeName : function(){
return funcio.apply(this, arguments);
+
    return this.name + ' ' + this.lastName;
else if (typeof old == 'function')
+
  }
return old.apply(this, arguments);
+
}
};
+
}
+
console.log( myApp.completeName() ); // Megan Fox
 
 
 
 
var persona = {};
 
afegirMetode(persona, "calculMatricula", function(){/* fer algo */});
 
afegirMetode(persona, "calculMatricula", function(a){/* fer una altre cosa */});
 
afegirMetode(persona, "calculMatricula", function(a,b){/* fer una altre cosa més */});
 
 
</source>
 
</source>
  
==== Exercici 9 : Sobrecàrrega de funcions ====
 
  
Donat el següent objecte:
+
En aquesta ocasió, si podem comprovar com this apunta al mateix objecte i busca la propietats 'name' i 'lastname' dins en lloc de remuntar-se fins el context global.
<source lang="java">
 
var usuaris = {
 
      noms : ["joan garcia", "jaume pontons", "ana riu", "marta aran", "alex fornell", "mariona cots"];
 
};
 
</source>
 
Crea una funció anomenada ''trobar'' que segons el número de paràmetres faci ;
 
* Si no es pasa cap paràmetre : Retorni directament l'array de noms.
 
* Si es pasa 1 paràmetre : Retorni  de la llista de noms aquell nom o noms que comencin per la cadena pasada com a únic argument.
 
* Si es pasen 2 paràmetres : Retorni  del llistat de noms aquells nom o noms que el nom sigui el primer paràmetre i el cognom el segon.
 
  
<!--:[[solucio sobrecarrega de funcions]]-->
+
===== Exercici 7 =====
  
'''Exercici 9.1'''  '''Sobrecarga'''
+
¿Quin és el seu valor?
  
Escrigui un programa que calculi diverses operacions, en cas de passar-li dos numeros han de tornar la divisió entre tots dos (No pot ser divisible per 0), en cas de passar-li tres paràmetres ha de tornar els dos valors d'una equació de segon grau.
+
<source lang="javascript">
 
+
var myApp = function(){
'''Exercici 9.2'''  '''Sobrecarga'''
+
  var name = "World"
 
+
  var sayHello = function(){
Escrigui un programa que calculi el àrea de diferents figures geomètriques (triangle, quadrat, rectangle, cercle, trapezi, etc.) sobrecarregant la funció àrea amb el número i tipus de arguments necessaris per cada tipus de figura.
+
    console.log( 'Hello, ' + this.name );
 
+
  };
== Clausures ==
+
  sayHello();
Una clausura és l'àmbit que es crea quan es declara una funció i es permet que aquesta pugui accedir i manipuli variables externes a ella, és a dir, ''són variables locals d'una funció mantingudes vives després que la funció hagi retornat''
+
};
Exemple:
+
<source lang="php">
+
myApp();
var missatge = "hola";
 
function accedirValor(){
 
alert(missatge);
 
}
 
 
</source>
 
</source>
  
De moment, sense sorpreses. La funció accedirValor pot accedir al valor de la variable externa missatge. Aquesta variables i aquesta funció estàn definides en l'àmbit global i aquest àmbit sempre existirà mentre duri el programa.
 
Però que pasaria si... :
 
  
<source lang="php">
+
Aquest comportament el podem comprovar si creem una variable global amb aquell nom pel qual estem preguntant
var missatge = "hola";
+
¿Quin és el seu valor?
var despres;
 
  
function accedirValor(){
+
<source lang="javascript">
var missatge_intern = "adeu";
+
var name = "Strange World";      //la variable pertenece a window
function accedirValorInternExtern(){
+
var myApp = function(){
alert("extern: " + missatge);       //les variables es mantenen vives
+
  var name = "World"            
alert("intern: " +missatge_intern);  
+
  var sayHello = function(){
}
+
    console.log( 'Hello, ' + this.name );       //this pertenece a window
despres = accedirValorInternExtern;        //es igual a accedirValorInterneExtern();
+
  };
}
+
 +
  sayHello();
 +
 +
};
 +
 +
myApp();  
  
accedirValor();
 
despres();
 
 
</source>
 
</source>
  
Conclusió:
+
La conseqüència d'aquest error és que un mètode no pot utilitzar funcions internes que l'ajudin a fer la seva feina perquè aquestes, no té accés a les seves propietats.
* accedirValor funciona correctament. Están definits en l'ambit global i per tant pot accedir sempre a les variables.
+
<!--
* despres()...no funciona com pensàvem, oi? La variable ''missatge_intern'' està viva! Per què? per les clausures.
+
'''solució'''
 +
:[[Solucio this]]
 +
-->
  
Quan declarem la funció accedirValorInternExtern dintre de la funció accedirValor, ''no estem només declarant la funció si no que estem creant una clausura que la envolta a ella i a les variables que estan en el seu àmbit en el moment de la declaració.''
+
===== Exercici 7.1 =====
 +
Mostra amb un framework unitari qui és l'objecte del argument this en cada cas:
  
Podem imaginar una clausura com una ''bombolla segura'' de la funció. Les variables que estan dintre del àmbit de la funció en la seva declaració i la mateixa funció estan dintre d'aquesta bombolla. Així aquesta funció disposa de tots els elements necessaris per poder-se executar.
+
<source lang="javascript">
 +
function unica(){return this;};
  
Anem a ampliar aquest concepte. Mireu la modificació que faig del codi anterior:
+
var replica = unica;
<source lang="java">
 
var missatge = "hola";
 
var despres;
 
  
function accedirValor(){
+
var objecte1 = {
var missatge_intern = "adeu";
+
  clon : unica
function accedirValorInternExtern(salutacio){
 
alert("extern: " + missatge);
 
alert("intern: " + missatge_intern);
 
alert("salutacio " + salutacio);
 
alert("fin " + fin);
 
}
 
despres = accedirValorInternExtern;
 
 
}
 
}
  
alert("mintern" + missatge_intern);
+
var objecte2 = {
alert(fin);
+
clon : unica
var fin = "tard";
+
}
accedirValor();
 
despres("fins despres");
 
 
</source>
 
</source>
  
Conclusió: la funció interna pot veure totes les variables que hi ha en aquest codi. Però com es aixó?
+
'''solució'''
 +
<!--
 +
:[[solucio funcio com a metode]]
 +
-->
 +
S'ha d'observar que el contexte canvia depenent de com s'invoca la funció. Pensa que la funció és la mateixa en tots els casos. Objecte1 i Objecte2 comparteixen la mateixa instància de la funció, fins i tot quan s'executa, la funció té accés al objecte que va invocar el mètode i pot realitzar operacions amb ell. Aquest és el principi de la programació orientada a objectes.
  
'''Conceptes relacionats amb les clausures'''
+
===== Exercici 8 =====
* Els paràmetres de la funció s'inclouen en la clausura d'aquesta funció.
 
* Totes les variables del àmbit extern, incloent les que es declaren després de la declaració de la funció, estan incloses.
 
* Dintre del mateix àmbit, les varibles que encara no s'han definit no poden ser referenciades més endavant.
 
  
=== Utilitzar les clausures per crear variables privades ===
 
 
És un ús molt comú utilitzar les clausures per definir les variables privades. De fet, ja ho has estat fent.
 
Exemple:
 
 
<source lang="java">
 
<source lang="java">
function Persona(){
+
var persona = {
var anys = 0;
+
    name: 'edu',
this.getAnys = function(){
+
    twitter: 'eiximenis',
return anys;
+
    twitterUrl: 'http://twitter.com/' + this.twitter
};
+
};
this.envellir = function(){
+
anys++;
+
console.log(persona.twitterUrl);
};
 
}
 
 
 
var joan = new Persona();
 
joan.envellir();
 
  
alert("no podem accedir: " + joan.anys);
 
alert("getanys: " + joan.getAnys());
 
 
</source>
 
</source>
  
  
 +
'''Exercici 8.1'''
  
Les clausures es diuen així perquè en realitat el que representen és a funcions que tenen accés a una sèrie de variables, lliures del seu propi àmbit (estan en un àmbit superior), i que fan ús d'elles mitjançant una sintaxi externa que és la que les estableix i li dóna el sentit (les tanca o clausura, d'aquí el nom).
+
<source lang="java">
  
Es veurà millor amb un exercici més apropiat com el següent codi JavaScript:
+
console.log(this);
  
'''Exercici 1. Digues que mostra.'''
+
function test(){
 +
 +
console.log(this);
 +
}
  
<source lang="java">
+
test();
 +
</source>
  
function concatenar(s1) {
+
'''Exercici 8.2'''
      return function(s2) {
 
        return s1 + ' ' + s2;
 
      };
 
}
 
  
var diHola = concatenar("Hola");
+
<source lang="java">
 +
var obj = {
 +
name: 'obj',
 +
run: function(){
 +
 +
this.value = 1;
 +
console.debug(this.name);
 +
}
 +
};
  
alert( diHola("visitante") );
+
obj.run();
 
</source>
 
</source>
  
 
+
'''Exercici 8.3'''  
És a dir, en la pràctica gràcies a l'ús d'una clausura hem definit una funció que permet assignar valors per a execució retardada. Això és una cosa realment útil, i no és l'única aplicació pràctica de les clausures, però gràcies a això podem habilitar tot un sistema d'execució en diferit de funcions JavaScript. Això ens permet crear punters a funcions pre-parametritzades i amb això crear un sistema d'esdeveniments, llançar accions periòdiques complexes i particularitzades amb setInterval o setTimeout ... i moltes altres coses.
 
 
 
'''Exercici 2. Digues que mostra.'''
 
  
 
<source lang="java">
 
<source lang="java">
 +
var obj = {
 +
name: 'obj',
 +
run: function(){
 +
this.value = 1;
 +
console.debug(this);
 +
 +
(function(){ // se crea un nuevo scope
 +
console.debug(this);
 +
})();
 +
 +
function test(){ // se crea un nuevo scope
 +
console.debug(this);
 +
}
 +
 +
test();
 +
}
 +
};
  
function dirHola2(nom) {
+
obj.run();
var texto = 'Hola ' + nom; // local variable
 
var dirAlerta= function() { alert(texto); }
 
return dirAlerta;
 
}
 
 
 
var dir2=dirHola2('Joan');
 
 
 
dir2();
 
 
</source>
 
</source>
  
 +
'''Exercici 8.3.1'''
 +
<source lang="java">
  
'''Exercici 3. Digues que mostra.'''
+
    var obj = {
 +
                name: 'obj',
 +
                run: function () {
 +
                    this.value = 1;
 +
                    console.log(this);
  
<source lang="java">
+
                    (function () { // se crea un nuevo scope
 +
                        console.log(this);
 +
                    })();
 +
                    that=this;
 +
                   
 +
                    function test(t) { // se crea un nuevo scope
 +
                        console.log(t);
 +
                    }
  
function dir666() {
+
                    test(that);
// Variable local que acaba en la clausura
+
                }
var num = 666;
+
            };
var dirAlerta= function() { alert(num); }
 
num++;
 
return dirAlerta;
 
}
 
  
 +
            obj.run();
  
var dirNombre=dir666();
 
 
dirNombre();
 
 
</source>
 
</source>
  
 
+
'''Exercici 8.4'''
'''Exercici 4. Digues que mostra.'''
 
  
 
<source lang="java">
 
<source lang="java">
 +
var obj = {
 +
    name: 'obj',
 +
    run: function(){
 +
        this.value = 1;
 +
        console.debug(this);
 +
       
 +
        (function(){
 +
            console.debug(this);
 +
        }).call(this); // se autoejecuta con el método call
 +
       
 +
        this.test = function(){
 +
            console.debug(this);
 +
        }
 +
       
 +
        this.test();
 +
    }
 +
};
 +
 +
obj.run();
  
var unicId = (function() {
+
</source>
  var comptador = 0;
+
<!--
  return function() {
+
:[[solucio exercicis this]]
    return "únic-id-" + comptador++;
+
-->
  };
 
})(); // Funció que s'auto-invoca i executa automàticament 
 
 
  
unicId();
+
==== Exercici 9 ====
  
unicId();
+
Digues que es mostrarà a cada alert. Explica-ho.
  
unicId();
+
<source lang="javascript">
 +
var missatge2 = "hola"
  
 +
function Nova (){
 +
var missatge2 = "adeu";
 +
this.missatge2 = "hello";
 +
alert("Missatge2 local: " + missatge2 + " ; Missatge2 global: " + this.missatge2);
 +
}
  
 +
var e = new Nova();
 +
alert(e.missatge2);
 +
alert("window : " + missatge2);
 
</source>
 
</source>
  
'''Exercici 5. Digues que mostra.'''
 
  
<source lang="java">
+
==== Invocació com constructor ====
 +
Per invocar una funció com a constructor no té cap misteri. S'ha de posar la paraula ''new'' davant de la funció.
 +
El que té de interessant és el que passa quan ho fem:
 +
* Es crea un objecte buit.
 +
* Aquest objecte es passa al constructor com paràmetre ''this'' i d'aquesta manera es converteix en el contexte de la funció.
 +
* En absència de qualsevol valor retornat de forma explícita, el nou objecte es retorna com a valor del constructor.
  
var crearContador = function () {
+
Que passaria si invoquem a la funció sense utilitzar la paraula ''new''?
    var cuenta, f;
+
* doncs que no es crea l'objecte i, llavors, les propietats i mètodes que pugui haver pertanyen al objecte ''window''.
    cuenta = 0;
 
    f = function () {
 
        cuenta = cuenta + 1;
 
        return cuenta;
 
    };
 
    return f;
 
};
 
var contador = crearContador();
 
/* contador es una funcion que no recibe argumentos
 
  y retorna una cuenta */
 
  
var a = contador();
+
Com sabem si una funció s'utilitza per crear objectes o son funcions normals?
var b = contador();
+
* Doncs no hi ha una manera estàndard
var c = contador();
+
* Per convenció si les funcions creen objectes llavors el nom de la funció comença amb lletra MAJÚSCULA.
  
var contador2 = crearContador(); // crear otro mas
+
<source lang="javascript">
var d = contador2();
+
function Cotxe(){
var e = contador2();
+
this.matricula = "";
var f = contador();  
+
}
 +
 
 +
/*cridem a la funció d'aquesta manera:*/
 +
var cotxe1 = new Cotxe();
 
</source>
 
</source>
  
Una cosa útil que les clausures poden fer és guardar l'estat intern. Recorda que una clausura és creada quan una funció interna referència a una variable de la funció externa.  
+
En  aquest exemple, la propietat ''matricula'' pertany a l'objecte ''cotxe1''. Si no haguéssim posat la paraula ''new'' el paràmetre ''this'' que s'utilitza dintre de la funció faria referència al objecte ''window''. Com s'ha posat la paraula ''new'' el paràmetre this fa referència al nou objecte creat.
  
En aquest exemple, cada invocació d'crearContador crea un nou abast("alcance") de compte, i la clausura circumdant a la funció interna f captura aquest abast.
+
==== Invocació amb els mètodes apply() i call() ====
---------------------------------------------------
 
*[http://www.variablenotfound.com/2012/10/closures-en-javascript-entiendelos-de.html Enllaç Complementari]
 
  
<!--:[[Solucio clausures]]-->
+
Javascript ens proporciona un mitjà per invocar a una funció i especificar de forma explícita qualsevol objecte que vulguem com a context. És a dir, podem decidir quin és el valor del paràmetre ''this'' quan cridem a una funció.
 
+
S'aconsegueix amb qualsevol dels dos mètodes que posseeixen les funcions: ''apply()'' i ''call()''.
== Funcions anònimes, autoexecutables i que retornen funcions ==
+
Sí, totes les funciones tenen dos mètodes disponibles, ja que son objectes de primera classe poden tindre propietats i mètodes igual que qualsevol altre objecte.
 +
Paràmetres del mètode apply():
 +
* L'objecte que s'utilitzarà com a context de la funció
 +
* Array de valors que s'utilitzaran com a arguments de la funció.
 +
Paràmetres del mètode call():
 +
* L'objecte que s'utilitzarà com a context de la funció
 +
* Llistat de valors que s'utilitzaran com a arguments de la funció.
  
Una funció anònima es pot definir sense que sigui asiganada a cap variable:
+
Exemple:
 +
<source lang="javascript">
 +
function exemple(){
 +
  var result = 0;
 +
  for (var i = 0; i < arguments.length; i++){
 +
        result += arguments[i];
 +
  }
 +
 
 +
  this.result = result;
 +
}
  
<source lang="java">
+
var objecte1 = {};
 +
var objecte2 = {};
  
function(qui) {
+
exemple.apply(objecte1,[1,2,3,4]);
 +
exemple.call(objecte2,5,6,7,8);
  
    alert("hola "+qui)
+
// en aquest punt objecte1.result tindrà el valor 10
 +
// i objecte2.result tindrà el valor 26
 +
</source>
  
}
+
== Les funcions sense nom ==
  
</source>
+
Les funcions sense nom s'utilitzen quan volem utilitzar-les posteriorment. Exemples:
No obstant això, fer això és completament inútil: definir ''una funció sense nom fa que sigui impossible ser executada més tard'', ja que sense un nom amb el qual accedir-hi és impossible trobar-la.
+
* quan les emmagatzemem en una variable,
Però ''podem executar-la en el mateix moment en què la definim''. Per fer-ho, només hem de tancar entre parèntesis, i després utilitzar uns nous parèntesi amb els paràmetres, com fem amb una funció normal.
+
* quan les posem com a mètodes d'objectes
 +
* quan les utilitzem com devolució de trucada (callback de timeout, callback de controladors d'events, etc).  
  
<source lang="java">
+
<source lang="javascript">
(function() { alert("hola món") })()
+
window.onload = function () {assert(true, "2");};
</source>
 
  
Per descomptat, podem passar-li paràmetres a la nostra funció autoexecutable. En el següent exemple, es passa com a paràmetre "món" a la funció:
 
  
<source lang="java">
+
var obj = {
(function(qui) {
+
            print : function () {assert(true, "1");}
 +
          }
 +
obj.print();
  
    alert("hola "+qui)
 
  
})("món")
+
setTimeout(function(){ assert(true, "3"); }, 500);
 
</source>
 
</source>
 +
L'ordre de sortida per pantalla és el següent : 1,2,3
 +
També podíem haber fet el següent amb el controlador de l'event càrrega de pàgina:
 +
<source lang="javascript">
 +
function bootMeUp(){
 +
    assert(true, "2");
 +
};
  
Pot semblar poc útil fer això ara, però més endavant veurem com és una fantàstica manera d'arreglar certs problemes.
+
window.onload = bootMeUp;
 
+
</source>
Per descomptat, una ''funció pot retornar una funció anònima''. Serà responsabilitat del programador assignar-la a una variable:
+
Però, per qué donar-li nom si mai més la cridarem? Realment necessitem que bootMeUp sigui un mètode del objecte window?
 +
A més a més, podem pensar que el mètode ''print'' és el nom de la funció anónima que l'assignem. NO!!. Demostra-ho utilitzant la propietat ''name'' de les funcions.
  
<source lang="java">
+
'''Funcions amb noms en linia'''
function saludator(qui) {
 
 
 
    return function() {
 
 
 
        alert("hola "+qui)
 
 
 
    }
 
  
 +
Però que succeeix si posem nom a les funcions sense nom?
 +
Exemple:
 +
<source lang="javascript">
 +
var persona = {
 +
  cantar : function xiular(n){...}
 
}
 
}
 
+
</source>
var saluda = saludator("món")
+
La funció ''xiular'' no la podem cridar fora de la funció. Peró sí la podem crear dintre, es a dir, ens interesa posar nom a les funcions sense nom quan les volem fer recursives.
 
+
<source lang="javascript">
saluda()
+
var persona = {
</source>
+
  cantar : function xiular(n){ return n > 1 ? xiular(n-1) + "-fiu" : "fiu"; }
 
 
podem executar la funció que s'ha retornat directament, sense assignar-la a cap variable:
 
 
 
<source lang="java">
 
function saludator(qui) {
 
 
 
    return function() {
 
 
 
        alert("hola "+qui)
 
 
 
    }
 
 
 
 
}
 
}
 
 
 
saludator("món")()
 
 
</source>
 
</source>
  
És clar, ningú et impedeix sobreescriure una funció amb una altra.
+
<!--=== Memoritzar valors calculats a la propia funció (Memoize) ===
  
<source lang="java">
+
La memorització (memoizacion) és el pas de crear una funció que pot recordar els seus valors calculats amb anterioritat. Així es pot incrementar considerablement el rendiment evitant càlculs complexes innecessaris que ja s'han calculat.
function saludator(qui) {
+
Exemple: Volem saber si un nombre és un nombre primer:
 +
<source lang="javascript">
 +
function esPrimer(valor){
 +
if(!esPrimer.cache) esPrimer.cache = {};
 +
if(esPrimer.cache[valor] != null) {
 +
return esPrimer.cache[valor];
 +
}
 +
var primer = valor != 1 // 1 no pot ser mai primer
 +
for(var i = 2; i < valor; i++){
 +
if(valor % i == 0){
 +
primer = false;
 +
break;
 +
}
 +
}
 +
return esPrimer.cache[valor] = primer;
 +
}
 +
esPrimer(5);
 +
</source>
 +
-->
  
    return function() {
+
== Paràmetres ...REST ==
  
        alert("hola "+qui)
+
Els paràmetres REST són un conjunt de paràmetres que s'emmagatzemen com array en un "paràmetre final" nomenclado amb ... nombreParametro.
 
+
Això ens permet gestionar la funció sense haver de controlar el nombre de paràmetres amb els quals aquesta és cridada.
    }
+
'''Important: només l'últim paràmetre pot ser REST.'''
  
 +
<source lang="javascript">
 +
function miFuncion(a, b, ...masArgumentos) {
 +
  console.log("a", a);
 +
  console.log("b", b);
 +
  console.log("masArgumentos", masArgumentos);
 +
  console.log("four", masArgumentos[1]);
 
}
 
}
  
+
miFuncion("one", "two", "three", "four", "five", "six");
  
saludator = saludator("món")
+
// Console Output:
 +
// a, one
 +
// b, two
 +
// manyMoreArgs, [three, four, five, six]
 +
// four, four
 +
</source>
  
saludator()
 
</source>
 
  
Aquí, la primera vegada que executem saludator ("món") ens retorna una funció anònima (que mostra "hola món"). Aquesta funció és assignada a la variable saludator, de manera que la segona vegada que truquem saludator (), estem executant la nova funció anònima (la del "hola món"), i la funció inicial original es perd per sempre.
+
== Sobrecàrrega de funcions ==
  
== Funcions immediates ==
+
En altres llenguatges de programació orientats a objectes, per sobrecarregar una funció se sol declarar distintes implementacions de mètodes amb el mateix nombre però amb un conjunt diferent de paràmetres. En Javascript no es fa d'aquesta manera. En Javascript es sobrecarreguen les funcions amb una única implementació que modifica el seu comportament mitjançant l'exàmen del nombre d'arguments que l'han proporcionat.
  
Una Funció immediata es basa en el concepte de les clausures.
+
És fàcil d'imaginar que es podria implementar la sobrecàrrega de funcions utilitzant una estructura del tipus if-then i else-if. Però no sempre ho podrem fer.  
Exemple de funció immediata:
+
 
<source lang="java">
+
Exemple: Funciò sobrecarregada de manera monolítica:
(function(){})()
+
<source lang="javascript">
</source>
+
var persona = {
 +
        calculMatricula = function(){
 +
  switch(arguments.length){
 +
case 0:
 +
// fer algo
 +
break;
 +
case 1:
 +
// fer una altre cosa
 +
break;
 +
case 2:
 +
// fer una altre cosa més
 +
break;
 +
... etc ...
 +
}
 +
}
 +
}
  
Analitzarem la construcció de la funció ignorant el primer grup de paréntesis.
 
<source lang="java">
 
(....)()
 
</source>
 
 
Sabem que podem fer la crida d'una funció utilitzant la sintaxis ''functionName()'', però en lloc del nom podem utilitzar qualsevol expressió que es refereixi a una de les seves instàncies.
 
<source lang="java">
 
var algunaFuncio = function(){...};
 
result = algunaFuncio();
 
// o també podem fer:
 
result = (algunaFuncio)();
 
 
</source>
 
</source>
  
Aixó significa que (---)(), el primer joc de parèntesis és un delimitador que tanca una expressió. El segon lloc de paréntesis és un operador.
+
Sin pasar argumentos
 +
<source lang="javascript">
 +
function suma(){
  
Ara en lloc d'una variable, posem la funció anónima directament.
 
<source lang="java">
 
(function(){...})();
 
</source>
 
  
Que fa aquesta funció?
+
switch(arguments.length){
* Crea una instància de la funció
+
case 0:
* Executa la funció
+
console.log("cero");
* Descarta la funció
+
break;
 +
case 1:
 +
 
 +
console.log(arguments[0]);
 +
break;
 +
case 2:
 +
  console.log(arguments[0]+arguments[1]);
 +
break;
 +
 +
}
 +
}
  
'''Per què és útil?'''
 
Podem crear un àmbit temporal que emmagatzemi el nostre estat.
 
  
<source lang="java">
+
suma();
(function(){
+
suma(2);
var numclicks = 0;
+
suma(3,4)
document.addEventListener("click", function(){alert(++numclicks);}, false);
 
})();
 
 
</source>
 
</source>
Lo important és observar que es crea una clausura pel controlador que inclou numclicks, llavors només ell pot fer referència a aquesta variable. Ningú més podrá modificar el seu valor.
 
Aquesta és una de les formes d'ús comú de les funcions immediates: com envoltoris simples e independents.
 
  
'''Es poden passar paràmetres a les funcions immediates?'''
+
'''SOLUCIÓ'''
Exemple:
+
 
<source lang="java">
+
Tenemos un array con una serie de nombre y apellidos ["joan garcia", "jaume pontons", "ana riu", "marta aran", "alex fornell", "mariona cots"], en caso de no pasar ningún argumento devolverá el array, si pasamos un trozo de cadena y lo encuentra, deberá añadirlo en un nuevo array y devolverlo, en caso de pasar 2 parámetros (nom, apellidos) deberá encontrarlos e introducirlos en el nuevo array.
(function(salutacio){alert(salutacio);})("Hola");
+
 
</source>
+
<!-- :[[Sol_sobrecarga]]-->
  
== Les funcions aninades ==
 
  
Les funcions que es troben dintre de altres funcions s'anomenen internes perque només podem accedir a elles dintre del codi de la funció que la engloba. A aquesta estructura l'anomenen funcions niades. Exemple:
+
Veurem una tècnica per ens permet crear diverses funcions (aparentment amb el mateix nom, però es diferència pel número de paràmetres) que poden escriure's com diferents, anónimes e independents i no com un bloc monolític if-then-else-if.
<source lang="es">
+
Tot aixó depén de una propietat poc coneguda de les funcions : la propietat length.
function saluda(quien) {
 
    function alertasaludo(quien) {
 
        alert("hola "+quien)
 
    }
 
    alertasaludo(quien)
 
  
}
+
=== length de funció ===
saluda("mundo")
 
</source>
 
  
Podem combinar funcions niades amb funcions que retornen funcions:
+
El paràmetre ''length'' de funció no ha de confondre's amb la propietat ''length'' del paràmetre arguments.
<source lang="es">
+
El paràmetre ''length'' de funció ens indica el número total de paràmetres formals amb els que s'ha declarat la funció.
function saludator(quien) {
+
La propietat ''length'' del paràmetre ''arguments'' ens indica el número total de parámetres que s'han passat a la funció en el moment de cridar-la.
    function alertasaludo() {
 
        alert("hola "+quien)
 
    }
 
  
    return alertasaludo
+
Exemple:
 +
<source lang="java">
 +
function max(a,b){
 +
  ...
 
}
 
}
  
var saluda = saludator("mundo")
+
max(1,4,5,7,23,234);
saluda()
+
 
 
</source>
 
</source>
 +
En aquest cas el paràmetre length de la funció max és 2 i la propietat length del paràmetre arguments és 6.
 +
 +
Utilitzarem aquest paràmetre per crear funcions sobrecarregades.
  
I lo anterior ho podem combinar amb funcions anónimes i auto-executables:
+
<source lang="java">
<source lang="es">
+
function afegirMetode(objecte, nom, funcio){
var saluda = (function(quien) {
+
var old = objecte[nom];
    function alertasaludo() {
+
objecte[nom] = function(){
        alert("hola "+quien)
+
if(funcio.length == arguments.length)
    }
+
return funcio.apply(this, arguments);
 +
else if (typeof old == 'function')
 +
return old.apply(this, arguments);
 +
};
 +
}
  
    return alertasaludo
 
})("mundo")
 
  
saluda();
+
var persona = {};
 +
afegirMetode(persona, "calculMatricula", function(){ fer algo  });
 +
afegirMetode(persona, "calculMatricula", function(a){ fer una altre cosa  });
 +
afegirMetode(persona, "calculMatricula", function(a,b){  fer una altre cosa més  });
 
</source>
 
</source>
  
Exemple del seu ús:
+
==== Exercici 9 : Sobrecàrrega de funcions ====
<source lang="es">
+
 
var parOimpar = (function() {
+
Donat el següent objecte:
    var hoy = new Date()
+
<source lang="java">
    if (new Date().getDate() % 2 == 0) {
+
var usuaris = {
        return function() { alert("hoy es dia par") }
+
      noms : ["joan garcia", "jaume pontons", "ana riu", "marta aran", "alex fornell", "mariona cots"]
    } else {
+
};
        return function() { alert("hoy es dia impar") }
 
    }
 
})()
 
 
 
parOimpar();
 
 
</source>
 
</source>
 +
Crea una funció anomenada ''trobar'' que segons el número de paràmetres faci ;
 +
* Si no es pasa cap paràmetre : Retorni directament l'array de noms.
 +
* Si es pasa 1 paràmetre : Retorni  de la llista de noms aquells noms que comencin per la cadena pasada com a únic argument.
 +
* Si es pasen 2 paràmetres : Retorni de la llista de noms aquells noms que el nom sigui el primer paràmetre i el cognom el segon.
  
 +
'''SOLUCIÓ'''
 +
<!--
 +
:[[solucio sobrecarrega de funcions]]
 +
-->
 +
'''Exercici 9.1'''  '''Sobrecarga'''
  
== Exercicis ==
+
Escrigui un programa que calculi diverses operacions, en cas de passar-li dos numeros han de tornar la divisió entre tots dos (No pot ser divisible per 0), en cas de passar-li tres paràmetres ha de tornar els dos valors d'una equació de segon grau.
  
 +
'''Exercici 9.2'''  '''Sobrecarga'''
  
Els Yahoo compten amb els dits : un, dos, tres i quatre. Coneixen el cero, pero no les quantitats
+
Escrigui un programa que calculi el àrea de diferents figures geomètriques (triangle, quadrat, rectangle, cercle, trapezi, etc.) sobrecarregant la funció àrea amb el número i tipus de arguments necessaris per cada tipus de figura.
negatives, per a ells son quantitats desconegudes. Conscients de la seva ignorància, sospiten de la
 
existència de una quantitat més gran que quatre: molts.
 
  
a) Funció següent :
+
== Clausures ==
 +
https://medium.com/@sergiodxa/definiendo-conceptos-closure-y-scope-en-javascript-9081f1e113e6
 +
Una clausura és l'àmbit que es crea quan es declara una funció i es permet que aquesta pugui accedir i manipuli variables externes a ella, és a dir, ''són variables locals d'una funció mantingudes vives després que la funció hagi retornat''
 +
Exemple:
 +
<source lang="php">
 +
var missatge = "hola";
 +
function accedirValor(){
 +
alert(missatge);
 +
}
 +
</source>
  
Per pode comptar, els yahoo coneixen la operació següent que transforma una quantitat en una altre
+
De moment, sense sorpreses. La funció accedirValor pot accedir al valor de la variable externa missatge. Aquesta variables i aquesta funció estàn definides en l'àmbit global i aquest àmbit sempre existirà mentre duri el programa.
de la següent manera :
+
Però que pasaria si... :
  
– El següent de lo desconegut continua sent desconegut
+
<source lang="php">
 +
var missatge = "hola";
 +
var despres;
  
– Per a les altres quantitats de zero a quatre, el següent és de un a molts respectivament.
+
function accedirValor(){
 +
var missatge_intern = "adeu";
 +
function accedirValorInternExtern(){
 +
alert("extern: " +  missatge);        //les variables es mantenen vives
 +
alert("intern: " +missatge_intern); 
 +
}
 +
despres = accedirValorInternExtern;        //es igual a accedirValorInterneExtern();
 +
}
  
– Per últim, el següent a molts és també molts.
+
accedirValor();
 +
despres();
 +
</source>
  
Crea el métode següent de la classe Yahoo :
+
Conclusió:  
 +
* accedirValor funciona correctament. Están definits en l'ambit global i per tant pot accedir sempre a les variables.
 +
* despres()...no funciona com pensàvem, oi? La variable ''missatge_intern'' està viva! Per què? per les clausures.
  
    Function Yahoo(){
+
Quan declarem la funció accedirValorInternExtern dintre de la funció accedirValor, ''no estem només declarant la funció si no que estem creant una clausura que la envolta a ella i a les variables que estan en el seu àmbit en el moment de la declaració.''
  
    var numeros = ....
+
Podem imaginar una clausura com una ''bombolla segura'' de la funció. Les variables que estan dintre del àmbit de la funció en la seva declaració i la mateixa funció estan dintre d'aquesta bombolla. Així aquesta funció disposa de tots els elements necessaris per poder-se executar.
  
    this.seguent = function(numero){....}
+
Anem a ampliar aquest concepte. Mireu la modificació que faig del codi anterior:
 +
<source lang="java">
 +
var missatge = "hola";
 +
var despres;
  
    }
+
function accedirValor(){
 +
var missatge_intern = "adeu";
 +
function accedirValorInternExtern(salutacio){
 +
alert("extern: " +  missatge);
 +
alert("intern: " + missatge_intern);
 +
alert("salutacio " + salutacio);
 +
alert("fin " + fin);
 +
}
 +
despres = accedirValorInternExtern;
 +
}
  
// utilització del mètode:
+
alert("mintern" + missatge_intern);
 +
alert(fin);
 +
var fin = "tard";
 +
accedirValor();
 +
despres("fins despres");
 +
</source>
  
var yahoo1 = new Yahoo();
+
Aquí estas creando una clausura. La creas en el momento que declaras una función dentro otra. Y permanecerá viva mientras viva la función declarada internamente.
  
alert(yahoo1.seguent(“desconegut”)); // ha de mostrar l'alert : 'desconegut'
+
Conclusió: la funció interna pot veure totes les variables que hi ha en aquest codi. Però com es aixó?
  
alert(yahoo1.seguent(“cero”)); // ha de mostrar l'alert : 'un'
+
'''Conceptes relacionats amb les clausures'''
 +
* Els paràmetres de la funció s'inclouen en la clausura d'aquesta funció.
 +
* Totes les variables del àmbit extern, incloent les que es declaren després de la declaració de la funció, estan incloses.
 +
* Dintre del mateix àmbit, les varibles que encara no s'han definit no poden ser referenciades més endavant.
  
alert(yahoo1.seguent(“quatre”)); // ha de mostrar l'alert : 'molts'
+
==Més Exemples de Clausures==
  
alert(yahoo1.seguent(“molts”)); // ha de mostrar l'alert : 'molts'
+
Supone el siguiente código, el ejemplo mas simple que se me ocurre.
  
 +
<source lang="javascript">
 +
function saltos(valor) {
 +
  var acumulado = 0;
 +
  return function() {
 +
    acumulado += valor;
 +
    return acumulado; 
 +
  };
 +
}
 +
</source>
  
 +
Aquí estas creando una clausura. La creas en el momento que declaras una función dentro otra. Y permanecerá viva mientras viva la función declarada internamente.
 +
<source lang="javascript">
 +
var quintos = saltos(5);
 +
quintos(); // retorna 5
 +
quintos(); // retorna 10
 +
quintos(); // retorna 15
 +
// y asi sigue... 20, 25, 30..
  
b) Funció suma :
+
</source>
 +
En definitiva, incluso después de que termina la ejecución de saltos(5), JavaScript mantiene una referencia a las variables declaradas en saltos (acumulado y valor), visibles para la función creada en el interior.
  
Els yahoos tenen un mètode suma que funciona de la següent manera:
 
  
– suma() --> retorna el valor desconegut
+
=== Utilitzar les clausures per crear variables privades ===
  
– suma(x) --> retorna el valor x (x pot ser zero, un, dos, tres, quatre, molts o desconegut)
+
És un ús molt comú utilitzar les clausures per definir les variables privades. De fet, ja ho has estat fent.
 
+
Exemple:
– suma(numero, x)  
+
<source lang="java">
 +
function Persona(){
 +
var anys = 0;
 +
this.getAnys = function(){
 +
return anys;
 +
};
 +
this.envellir = function(){
 +
anys++;
 +
};
 +
}
 +
 
 +
var joan = new Persona();
 +
joan.envellir();
 +
 
 +
alert("no podem accedir: " + joan.anys);
 +
alert("getanys: " + joan.getAnys());
 +
</source>
  
 si numero és desconegut, retorna desconegut sigui quin sigui x
 
  
 si numero és zero, retorna lo mateix que suma(x)
 
  
 si numero és uno, retorna siguiente(x)
+
Les clausures es diuen així perquè en realitat el que representen és a funcions que tenen accés a una sèrie de variables, lliures del seu propi àmbit (estan en un àmbit superior), i que fan ús d'elles mitjançant una sintaxi externa que és la que les estableix i li dóna el sentit (les tanca o clausura, d'aquí el nom).
  
 si numero és dos, retorna siguiente(siguiente(x))
+
Es veurà millor amb un exercici més apropiat com el següent codi JavaScript:
  
 .....
+
'''Exercici 1. Digues que mostra.'''
 +
 
 +
<source lang="java">
 +
 
 +
function concatenar(s1) {
 +
      return function(s2) {
 +
        return s1 + ' ' + s2;
 +
      };
 +
}
 +
 
 +
var diHola = concatenar("Hola");
 +
 
 +
alert( diHola("visitante") );
 +
</source>
 +
 
 +
 
 +
És a dir, en la pràctica gràcies a l'ús d'una clausura hem definit una funció que permet assignar valors per a execució retardada. Això és una cosa realment útil, i no és l'única aplicació pràctica de les clausures, però gràcies a això podem habilitar tot un sistema d'execució en diferit de funcions JavaScript. Això ens permet crear punters a funcions pre-parametritzades i amb això crear un sistema d'esdeveniments, llançar accions periòdiques complexes i particularitzades amb setInterval o setTimeout ... i moltes altres coses.
 +
 
 +
'''Exercici 2. Digues que mostra.'''
 +
 
 +
<source lang="java">
 +
 
 +
function dirHola2(nom) {
 +
var texto = 'Hola ' + nom; // local variable
 +
var dirAlerta= function() { alert(texto); }
 +
return dirAlerta;
 +
}
 +
 
 +
var dir2=dirHola2('Joan');
 +
 
 +
dir2();
 +
</source>
 +
 
 +
 
 +
'''Exercici 3. Digues que mostra.'''
 +
 
 +
<source lang="java">
 +
 
 +
function dir666() {
 +
// Variable local que acaba en la clausura
 +
var num = 666;
 +
var dirAlerta= function() { alert(num); }
 +
num++;
 +
return dirAlerta;
 +
}
 +
 
 +
 
 +
var dirNombre=dir666();
 +
 
 +
dirNombre();
 +
</source>
 +
 
 +
 
 +
'''Exercici 4. Digues que mostra.'''
 +
 
 +
<source lang="java">
 +
 
 +
var unicId = (function() {
 +
  var comptador = 0;
 +
  return function() {
 +
    return "únic-id-" + comptador++;
 +
  };
 +
})(); // Funció que s'auto-invoca i executa automàticament 
 +
 +
 
 +
unicId();
 +
 
 +
unicId();
 +
 
 +
unicId();
 +
 
 +
 
 +
</source>
 +
 
 +
'''Exercici 5. Digues que mostra.'''
 +
 
 +
<source lang="java">
 +
 
 +
 
 +
            var crearContador = function () {
 +
                var cuenta, f;
 +
                cuenta = 0;
 +
                f = function () {
 +
                    cuenta = cuenta + 1;
 +
                    return cuenta;
 +
                };
 +
                return f;
 +
            };
 +
            var contador = crearContador();
 +
            /* contador es una funcion que no recibe argumentos
 +
            y retorna una cuenta */
 +
 
 +
            var a = contador();
 +
            console.log(a);
 +
            var b = contador();
 +
            console.log(b);
 +
            var c = contador();
 +
            console.log(c);
 +
 
 +
            var contador2 = crearContador(); // crear otro mas
 +
            var d = contador2();
 +
            console.log(d);
 +
            var e = contador2();
 +
            console.log(e);
 +
            var f = contador2();
 +
            console.log(f);
 +
 
 +
</source>
 +
<!-- Comentat Mónica
 +
:[[Solucio clausures]]
 +
-->
 +
 
 +
Una cosa útil que les clausures poden fer és guardar l'estat intern. Recorda que una clausura és creada quan una funció interna referència a una variable de la funció externa.
 +
 
 +
En aquest exemple, cada invocació d'crearContador crea un nou abast("alcance") de compte, i la clausura circumdant a la funció interna f captura aquest abast.
 +
---------------------------------------------------
 +
http://www.variablenotfound.com/2012/10/closures-en-javascript-entiendelos-de.html Enllaç Complementari
 +
 
 +
== Funcions anònimes, autoexecutables i que retornen funcions ==
 +
Tracta d'evitar utilitzar variables globals, per temes de securetat. Per exemple, una variable global llistaUsuaris.
 +
 
 +
Una funció anònima es pot definir sense que sigui asiganada a cap variable:
 +
 
 +
<source lang="java">
 +
 
 +
function(qui) {
 +
 
 +
    alert("hola "+qui)
 +
 
 +
}
 +
 
 +
</source>
 +
No obstant això, fer això és completament inútil: definir ''una funció sense nom fa que sigui impossible ser executada més tard'', ja que sense un nom amb el qual accedir-hi és impossible trobar-la.
 +
Però ''podem executar-la en el mateix moment en què la definim''. Per fer-ho, només hem de tancar entre parèntesis, i després utilitzar uns nous parèntesi amb els paràmetres, com fem amb una funció normal.
 +
 
 +
<source lang="java">
 +
(function() { alert("hola món") })()
 +
</source>
 +
 
 +
Per descomptat, podem passar-li paràmetres a la nostra funció autoexecutable. En el següent exemple, es passa com a paràmetre "món" a la funció:
 +
 
 +
<source lang="java">
 +
(function(qui) {
 +
 
 +
    alert("hola "+qui)
 +
 
 +
})("món")
 +
</source>
 +
 
 +
Pot semblar poc útil fer això ara, però més endavant veurem com és una fantàstica manera d'arreglar certs problemes.
 +
 
 +
Per descomptat, una ''funció pot retornar una funció anònima''. Serà responsabilitat del programador assignar-la a una variable:
 +
 
 +
<source lang="java">
 +
function saludator(qui) {
 +
    return function() {
 +
        alert("hola "+qui)
 +
    }
 +
}
 +
 
 +
var saluda = saludator("món")
 +
saluda()
 +
</source>
 +
 
 +
podem executar la funció que s'ha retornat directament, sense assignar-la a cap variable:
 +
 
 +
<source lang="java">
 +
function saludator(qui) {
 +
    return function() {
 +
        alert("hola "+qui)
 +
    }
 +
}
 +
 
 +
saludator("món")()
 +
</source>
 +
 
 +
És clar, ningú et impedeix sobreescriure una funció amb una altra.
 +
 
 +
<source lang="java">
 +
function saludator(qui) {
 +
 
 +
    return function() {
 +
 
 +
        alert("hola "+qui)
 +
 
 +
    }
 +
 
 +
}
 +
 
 +
 +
 
 +
saludator = saludator("món")
 +
 
 +
saludator()
 +
</source>
 +
 
 +
Aquí, la primera vegada que executem saludator ("món") ens retorna una funció anònima (que mostra "hola món"). Aquesta funció és assignada a la variable saludator, de manera que la segona vegada que truquem saludator (), estem executant la nova funció anònima (la del "hola món"), i la funció inicial original es perd per sempre.
 +
 
 +
== Funcions immediates ==
 +
 
 +
Una Funció immediata es basa en el concepte de les clausures.
 +
Exemple de funció immediata:
 +
<source lang="java">
 +
(function(){})()
 +
</source>
 +
 
 +
Analitzarem la construcció de la funció ignorant el primer grup de paréntesis.
 +
<source lang="java">
 +
(....)()
 +
</source>
 +
 
 +
Sabem que podem fer la crida d'una funció utilitzant la sintaxis ''functionName()'', però en lloc del nom podem utilitzar qualsevol expressió que es refereixi a una de les seves instàncies.
 +
<source lang="java">
 +
var algunaFuncio = function(){...};
 +
result = algunaFuncio();
 +
// o també podem fer:
 +
result = (algunaFuncio)();
 +
</source>
 +
 
 +
Aixó significa que (---)(), el primer joc de parèntesis és un delimitador que tanca una expressió. El segon lloc de paréntesis és un operador.
 +
 
 +
Ara en lloc d'una variable, posem la funció anónima directament.
 +
<source lang="java">
 +
(function(){...})();
 +
</source>
 +
 
 +
Que fa aquesta funció?
 +
* Crea una instància de la funció
 +
* Executa la funció
 +
* Descarta la funció
 +
 
 +
'''Per què és útil?'''
 +
Podem crear un àmbit temporal que emmagatzemi el nostre estat.
 +
 
 +
<source lang="java">
 +
(function(){
 +
var numclicks = 0;
 +
document.addEventListener("click", function(){alert(++numclicks);}, false);
 +
})();
 +
</source>
 +
Lo important és observar que es crea una clausura pel controlador que inclou numclicks, llavors només ell pot fer referència a aquesta variable. Ningú més podrá modificar el seu valor.
 +
Aquesta és una de les formes d'ús comú de les funcions immediates: com envoltoris simples e independents.
 +
 
 +
'''Es poden passar paràmetres a les funcions immediates?'''
 +
Exemple:
 +
<source lang="java">
 +
(function(salutacio){alert(salutacio);})("Hola");
 +
</source>
 +
 
 +
== Les funcions aniuades ==
 +
 
 +
Les funcions que es troben dintre de altres funcions s'anomenen internes perque només podem accedir a elles dintre del codi de la funció que la engloba. A aquesta estructura l'anomenen funcions niades. Exemple:
 +
<source lang="es">
 +
function saluda(quien) {
 +
    function alertasaludo(quien) {
 +
        alert("hola "+quien)
 +
    }
 +
    alertasaludo(quien)
 +
 
 +
}
 +
saluda("mundo")
 +
</source>
 +
 
 +
Podem combinar funcions niades amb funcions que retornen funcions:
 +
<source lang="es">
 +
function saludator(quien) {
 +
    function alertasaludo() {
 +
        alert("hola "+quien)
 +
    }
 +
 
 +
    return alertasaludo
 +
}
 +
 
 +
var saluda = saludator("mundo")
 +
saluda()
 +
</source>
 +
 
 +
I lo anterior ho podem combinar amb funcions anónimes i auto-executables:
 +
<source lang="es">
 +
var saluda = (function(quien) {
 +
    function alertasaludo() {
 +
        alert("hola "+quien)
 +
    }
 +
 
 +
    return alertasaludo
 +
})("mundo")
 +
 
 +
saluda();
 +
</source>
 +
 
 +
Exemple del seu ús:
 +
<source lang="es">
 +
var parOimpar = (function() {
 +
    var hoy = new Date()
 +
    if (new Date().getDate() % 2 == 0) {
 +
        return function() { alert("hoy es dia par") }
 +
    } else {
 +
        return function() { alert("hoy es dia impar") }
 +
    }
 +
})()
 +
 
 +
parOimpar();
 +
</source>
 +
 
 +
<source lang="javacript">
 +
 
 +
        function funcion1(){ 
 +
 
 +
let funcion1 ="funcion1";
 +
 +
function funcion2(){
 +
 
 +
let funcion2="funcion2";
 +
 
 +
function funcion3(){
 +
 
 +
return "Solución";
 +
             
 +
}
 +
 
 +
                return funcion3;
 +
       
 +
}
 +
 
 +
      return funcion2;
 +
}
 +
 
 +
 
 +
var resultado1= funcion1();
 +
var resultado2= resultado1();
 +
var resultado= resultado2();
 +
 
 +
var otraForma= funcion1()()();
 +
 +
</source>
 +
 
 +
== Exercicis ==
 +
<!-- Comentat per Mónica
 +
'''Exercici RELLOTGE'''
 +
 
 +
http://www.w3schools.com/js/js_obj_date.asp
 +
 
 +
http://www.w3schools.com/jsref/jsref_obj_date.asp
 +
 
 +
Crea una classe anomenada Rellotge. Aquesta classe ha de tenir les següents funcions:
 +
 
 +
– '''Constructor Rellotge :''' Posa en marxa el rellotge
 +
 
 +
– '''GetTime :''' Retorna el temps en segons des de que es va crear el rellotge
 +
 
 +
– '''StopTime:''' Para el rellotge però emmagatzema els segons que ha estat funcionant.
 +
 
 +
– '''StartTime:''' Torna a posar en marxa el rellotge. El temps que ha estat parat no s'ha de tenir en compte al calcular el temps.
 +
 
 +
– '''setFunctionOnTime(time, function) :''' Emmagatzema una funció per a executar-la com a molt d'hora en el numero de segons que indiqui time.
 +
 
 +
– '''Execute :''' Executa totes les funcions, una darrera l'altre, que estan emmagatzemades si el seu time es inferior o igual que el temps actual, es a dir, el temps en segons que ha passat des de que es va posar en marxa.
 +
 
 +
Crea un programa on es pugui veure que aquesta classe funciona correctament.
 +
 
 +
-->
 +
 
 +
 
 +
'''Exercici YAHOO'''
 +
 
 +
Els Yahoo compten amb els dits : un, dos, tres i quatre. Coneixen el cero, però no les quantitats
 +
negatives, per a ells son quantitats desconegudes. Conscients de la seva ignorància, sospiten de la
 +
existència de una quantitat més gran que quatre: molts.
 +
 
 +
a) Funció següent :
 +
 
 +
Per poder comptar, els Yahoo coneixen la operació següent que transforma una quantitat en una altre
 +
de la següent manera :
 +
 
 +
– El següent de lo desconegut continua sent desconegut
 +
 
 +
– Per a les altres quantitats de zero a quatre, el següent és de un a molts respectivament.
 +
 
 +
– Per últim, el següent a molts és també molts.
 +
 
 +
Crea el mètode següent de la classe Yahoo :
 +
 
 +
<source lang="java">
 +
    Function Yahoo(){
 +
 
 +
    var numeros = ....
 +
 
 +
    this.seguent = function(numero){....}
 +
 
 +
    }
 +
 
 +
// utilització del mètode:
 +
 
 +
var yahoo1 = new Yahoo();
 +
 
 +
alert(yahoo1.seguent(“desconegut”)); // ha de mostrar l'alert : 'desconegut'
 +
 
 +
alert(yahoo1.seguent(“cero”)); // ha de mostrar l'alert : 'un'
 +
 
 +
alert(yahoo1.seguent(“quatre”)); // ha de mostrar l'alert : 'molts'
 +
 
 +
alert(yahoo1.seguent(“molts”)); // ha de mostrar l'alert : 'molts'
 +
 
 +
</source>
 +
 
 +
b) Funció suma :
 +
 
 +
Els Yahoos tenen un mètode suma que funciona de la següent manera:
 +
 
 +
– suma(): retorna el valor desconegut
 +
 
 +
– suma(x): retorna el valor x (x pot ser zero, un, dos, tres, quatre, molts o desconegut)
 +
 
 +
– suma(numero, x)
 +
 
 +
 si numero és desconegut, retorna desconegut sigui quin sigui x
 +
 
 +
 si numero és zero, retorna lo mateix que suma(x)
 +
 
 +
 si numero és u, retorna seguent(x)
 +
 
 +
 si numero és dos, retorna seguent(seguent(x))
 +
 
 +
 .....
  
 
 si numero és molts, retorna molts sigui quin sigui x.
 
 si numero és molts, retorna molts sigui quin sigui x.
 +
 +
 +
<!--
 +
'''SOLUCIó'''
 +
 +
:[[Solucio Yahoo rellotge]]
 +
-->
 +
 +
<!--
 +
'''Exercici classe persona'''
 +
 +
 +
Defineix la classe Persona que tindrà les propietats nom, edat, ciutat i telèfon. La propietat edat serà privada, les altres públiques.
 +
 +
El constructor de la classe admetrà 2, 3 o 4 paràmetres. Si es crida amb 2 paràmetres, aquests seran el nom i l'edat. Si es crida amb 3: el nom, l'edat i la ciutat. Finalment, si es crida amb 4: el nom, l'edat, la ciutat i el telèfon.
 +
 +
A aquelles propietats que no inicialitzi el constructor se'ls assignarà el valor "desconegut".
 +
 +
Defineix el mètode info que retornarà un string amb les dades de l'objecte: "nom:***, edat:**, ciutat:******, telèfon:*********.
 +
 +
Defineix el mètode aniversari que incrementarà en 1 l'edat.
 +
 +
Crea un script que comprovi les tres maneres de cridar el constructor i el mètode aniversari.
 +
-->
 +
<!--
 +
'''Encapçalaments'''
 +
 +
Crea un script que escrigui en una pàgina web els encapçalaments desde <source lang="php"><h1></source> fins a <source lang="php"><h6></source>, amb un text que posi:
 +
 +
encapçalament de nivell X
 +
 +
on X és el nivell que estem escrivint.
 +
 +
'''Muestra Fecha'''
 +
 +
Realizar un programa que pasados 20 segundos, nos muestre una vez la fecha actual del sistema.
 +
 +
 +
''' Muestra datos'''
 +
Haz un programa que reciba cadenas del tipo: “nombre:apellidos:telefono:email:codigopostal” y que te muestre:
 +
 +
• El código postal.
 +
 +
• Los apellidos
 +
 +
• El email.
 +
 +
• Suponiendo un formato de email “direccion@servidor” te muestre el servidor asociado.
 +
 +
-->
 +
<!-- Comentat per Mónica
 +
'''Exercici RELLOTGE'''
 +
-->
 +
<!--
 +
*rellotge.js (definició de la classe rellotge):
 +
 +
<source lang="javascript">
 +
function Rellotge(){
 +
var inici=new Date();
 +
var acumulat=0;
 +
var times = new Array();
 +
var funcions = new Array();
 +
var executada = new Array();
 +
 +
this.getTime=function(){
 +
//si el rellotge esta arrancat inici no és null
 +
 +
if (inici){
 +
var now= new Date();
 +
return (now-inici+acumulat)/1000;
 +
}
 +
else {
 +
return acumulat/1000;
 +
}
 +
}
 +
 +
this.startTime=function() {
 +
// si esta aturat
 +
if(!inici){
 +
inici=new Date();
 +
}
 +
 +
}
 +
 +
this.stopTime=function() {
 +
// si està iniciat
 +
if(inici){
 +
var now= new Date();
 +
acumulat+=now-inici;
 +
inici=null;
 +
}
 +
}
 +
 +
this.setFunctionOnTime=function(_time,_function) {
 +
times.push(_time);
 +
funcions.push(_function);
 +
executada.push(false);
 +
}
 +
 +
this.execute=function() {
 +
var segons=this.getTime();
 +
 +
for(i in times) {
 +
if(times[i]<=segons && !executada[i]){
 +
funcions[i]();
 +
executada[i]=true;
 +
}
 +
}
 +
}
 +
}
 +
</source>
 +
 +
*proves_rellotge.html (pàgina de proves per a la classe rellotge):
 +
 +
<source lang="HTML">
 +
<html>
 +
<body>
 +
<h1>
 +
rellotge
 +
</h1>
 +
 +
<button onclick="gettime()">get time</button>
 +
<br>
 +
<button onclick="stoptime()">stop time</button>
 +
<br>
 +
<button onclick="starttime()">start time</button>
 +
<br>
 +
<button onclick="execute()">execute</button>
 +
<br>
 +
 +
<h1 id="temps"></h1>
 +
<p id="text"></p>
 +
 +
<script src=rellotge.js></script>
 +
 +
<script type="text/javascript">
 +
 +
var myRellotge=new Rellotge();
 +
 +
myRellotge.setFunctionOnTime(5,funcio1);
 +
myRellotge.setFunctionOnTime(10,funcio2);
 +
myRellotge.setFunctionOnTime(15,funcio3);
 +
myRellotge.setFunctionOnTime(20,funcio1);
 +
myRellotge.setFunctionOnTime(25,funcio2);
 +
 +
function execute() {
 +
myRellotge.execute();
 +
}
 +
 +
function gettime() {
 +
alert(myRellotge.getTime());
 +
}
 +
 +
function stoptime() {
 +
myRellotge.stopTime();
 +
}
 +
 +
function starttime() {
 +
myRellotge.startTime();
 +
}
 +
 +
setInterval(function(){document.getElementById("temps").innerHTML=myRellotge.getTime()},1000);
 +
 +
 +
function funcio1(){
 +
document.getElementById("text").innerHTML+="<br>Funció 1";
 +
}
 +
function funcio2(){
 +
document.getElementById("text").innerHTML+="<br>Funció 2";
 +
}
 +
function funcio3(){
 +
document.getElementById("text").innerHTML+="<br>Funció 3";
 +
}
 +
 +
</script>
 +
</body>
 +
</html>
 +
</source>
 +
-->
 +
 +
<!-- Comentat per Mónica
 +
 +
'''Exercici YAHOO'''
 +
 +
 +
*yahoo.js (definició de la classe Yahoo):
 +
 +
<source lang="javascript">
 +
function Yahoo() {
 +
 +
this.seguent=function(num) {
 +
 +
switch(num) {
 +
case "zero":
 +
return "un";
 +
case "un":
 +
return "dos";
 +
case "dos":
 +
return "tres";
 +
case "tres":
 +
return "quatre";
 +
case "quatre":
 +
return "molts";
 +
case "molts":
 +
return "molts";
 +
default:
 +
return "desconegut";
 +
}
 +
}
 +
 +
this.suma=function (){
 +
if(arguments.length==0)
 +
return "desconegut";
 +
 +
if(arguments.length==1) {
 +
var a=arguments[0]
 +
if(a=="zero" || a=="un" || a=="dos" || a=="tres" || a=="quatre" || a=="molts")
 +
return a;
 +
else
 +
return "desconegut";
 +
}
 +
 +
if(arguments.length==2){
 +
var a=arguments[0];
 +
var b=arguments[1];
 +
if (a=="desconegut")
 +
return "desconegut";
 +
if(a=="zero")
 +
return this.suma(b);
 +
if(a=="un")
 +
return this.seguent(b);
 +
if(a=="dos")
 +
return this.seguent(this.seguent(b));
 +
if(a=="tres")
 +
return this.seguent(this.seguent(this.seguent(b)));
 +
if(a=="quatre")
 +
return this.seguent(this.seguent(this.seguent(this.seguent(b))));
 +
if(a=="molts")
 +
return "molts";
 +
return "desconegut";
 +
}
 +
}
 +
 +
}
 +
</source>
 +
 +
*proves_yahoo.html (pàgina de proves)
 +
<source lang="HTML">
 +
<html>
 +
 +
<body>
 +
<h1>
 +
Proves objecte Yahoo
 +
</h1>
 +
 +
<script src=yahoo.js></script>
 +
<script type="text/javascript">
 +
 +
 +
var yahoo1 = new Yahoo();
 +
 +
document.write('<br>yahoo1.seguent("desconegut"):'+yahoo1.seguent("desconegut"));
 +
document.write('<br>yahoo1.seguent("zero"):'+yahoo1.seguent("zero"));
 +
document.write('<br>yahoo1.seguent("un"):'+yahoo1.seguent("un"));
 +
document.write('<br>yahoo1.seguent("dos"):'+yahoo1.seguent("dos"));
 +
document.write('<br>yahoo1.seguent("tres"):'+yahoo1.seguent("tres"));
 +
document.write('<br>yahoo1.seguent("quatre"):'+yahoo1.seguent("quatre"));
 +
document.write('<br>yahoo1.seguent("molts"):'+yahoo1.seguent("molts"));
 +
document.write('<br>yahoo1.seguent("asdfasdfsdf"):'+yahoo1.seguent("asdfasdfsdf"));
 +
 +
document.write('<br>yahoo1.suma():'+yahoo1.suma());
 +
document.write('<br>yahoo1.suma("un"):'+yahoo1.suma("un"));
 +
document.write('<br>yahoo1.suma("zero","dos"):'+yahoo1.suma("zero","dos"));
 +
document.write('<br>yahoo1.suma("quatre","dos"):'+yahoo1.suma("quatre","dos"));
 +
document.write('<br>yahoo1.suma("un","dos"):'+yahoo1.suma("un","dos"));
 +
document.write('<br>yahoo1.suma("desconegut","tres"):'+yahoo1.suma("desconegut","tres"));
 +
document.write('<br>yahoo1.suma("zero","un"):'+yahoo1.suma("zero","un"));
 +
document.write('<br>yahoo1.suma("quatre","zero"):'+yahoo1.suma("quatre","zero"));
 +
document.write('<br>yahoo1.suma("quatre","un"):'+yahoo1.suma("quatre","un"));
 +
document.write('<br>yahoo1.suma("un","desconegut"):'+yahoo1.suma("un","desconegut"));
 +
document.write('<br>yahoo1.suma("molts","dos"):'+yahoo1.suma("molts","dos"));
 +
document.write('<br>yahoo1.suma("molts","molts"):'+yahoo1.suma("molts","molts"));
 +
document.write('<br>yahoo1.suma("desconegut","molts"):'+yahoo1.suma("desconegut","molts"));
 +
document.write('<br>yahoo1.suma("molts","desconegut"):'+yahoo1.suma("molts","desconegut"));
 +
document.write('<br>yahoo1.suma("desconegut","desconegut"):'+yahoo1.suma("desconegut","desconegut"));
 +
 +
 +
</script>
 +
 +
 +
</body>
 +
</html>
 +
</source>
 +
-->
  
 
= Bibliografia =
 
= Bibliografia =

Revisió de 10:28, 15 nov 2023

Funcions

http://es6-features.org/ desestructuración. spread vs rest

https://www.arquitecturajava.com/javascript-closure-funcionamiento/

https://cybmeta.com/var-let-y-const-en-javascript

Comprovació i Depuració

Crear conjunts de proves efectius per al codi sempre és important, per això ho tractem ara, abans de continuar amb les funcions. En Javascript no solament ens trobem amb els típics problemes per garantir la qualitat sinó que també ens trobem amb obstacles a l'hora de determinar si el nostre codi funciona en tots els navegadors amb els quals hem decidit ser compatibles.

Hi ha dos importants enfocaments per depurar Javascript: el registre i els punts de parada. Tots dos són útils per respondre a la pregunta crucial, "Què està passant amb el meu codi?".

Registre

Les declaracions de registre, com les quals fem en executar console.log(), són part del codi (encara que sigui de forma temporal) i resulten pràctiques en un entorn multinavegador. Les consoles del navegador han millorat molt el procés de registre mes allà de la tècnica d'afegir una alerta. Podem escriure totes les nostres declaracions de registre en la consola i accedir a elles de forma immediata o amb posterioritat sense afectar al flux normal del programa, alguna cosa que no és possible amb alert().

El registre és perfecte per buscar quin pot ser l'estat de les coses mentre s'està executant el codi però, en algunes ocasions, volem detenir l'acció i fer un cop d'ull. Aquí és on apareixen els punts de parada.

/*Activa el depurador i ves a la "consola" a vore que mostra*/
a = 5;
b = 6;
c = a + b;
console.log(c);

Punts de parada

Detenen l'execució d'un comando en una línia de codi concreta, detenint el navegador. Això ens permet investigar sense presses l'estat de tot tipus de coses en el punt de parada, incloent totes les variables accessibles, el context i la cadena d'abast.

Generació de proves

Les bones proves exhibeixen tres importants característiques:

  • Repetibilitat: Els resultats han de ser molt fàcils de reproduir. Les proves que s'executen en repetides ocasions sempre haurien de produir exactament els mateixos resultats. Les proves no depenen de factors externs com la xarxa o la CPU.
  • Simplicitat: Les proves han de centrar-se a comprovar un únic element. Hem de llevar el CSS i l'HTML com sigui possible sense afectar la intenció del cas de prova.
  • Independència: Les proves han d'executar-se en solitari. Cal evitar que els resultats d'una prova depenguin d'una altra.

Enfocaments per crear proves:

  • Deconstructius: El codi existent es descompon per aïllar un problema, eliminant alguna cosa que no està relacionat amb la qüestió.
  • Constructius: Comencem a partir d'un cas reduït ben conegut i creguem fins que som capaços de reproduir l'error en qüestió.

Exemple de cas de prova DOM empleat per comprovar JQuery:

<script src="dist/jquery.js"></script>
<script>
  $(document).ready(function() {
    $("#test").append("test");
  });
</script>
<style>
  #test { width: 100px; height: 100px; background: red; }
</style>
<div id="test"></div>

Entorns de comprovació

Aquesta eina serveix a una necessitat única: mostrar els resultats de les proves, fent que sigui més fàcil determinar quins han sortit bé i quins han fallat. Els entorns de comprovació ens ajuden a aconseguir aquest objectiu sense haver de preocupar-nos per una altra cosa que no sigui crear les proves i organitzar-les en conjunts. Els entorns de comprovació única de Javascript solen proporcionar alguns components clau:

  • un executor de proves,
  • agrupacions de proves i
  • aserveracions.

Alguns ofereixen a més l'habilitat d'execució asincrónica.

QUnit

És l'entorn que va ser creat per provar jQuery. Ha sobrepassat les seves metes inicials i ara s'ha convertit en una utilitat independent. QUnit es va dissenyar bàsicament per ser una solució senzilla, proporcionant una API mínima però fàcil d'utilitzar. Característiques:

  • API senzilla
  • compatible amb la comprovació asincrónica.
  • No es limita a jQuery

web: http://qunitjs.com/

Exemple d'ús:

EJEMPLO 1

<html>
   <head>
      <meta charset = "utf-8">
      <title>QUnit basic example</title>
      <link rel = "stylesheet" href = "https://code.jquery.com/qunit/qunit-1.22.0.css">
      <script src = "https://code.jquery.com/qunit/qunit-1.22.0.js"></script>
   </head>
   
   <body>
      <div id = "qunit"></div>
      <div id = "qunit-fixture"></div> 
      
      <script>
         function square(x) {
            return x * x;
         }
         QUnit.test( "TestSquare", function( assert ) {
            var result = square(2);
            assert.equal( result, "4", "square(2) should be 4." );
         });
      </script>
   </body>
</html>


EJERCICIO

Se desea hacer un test de pruebas con la función ponerAlRevés, por ello deberá ponerse valores negativos, positivos, float, palabra... y las cadenas con alguna coma, mayúscula.



function posarReves(opcio, text) {
	var separator = " ";
	if(opcio == 0){
		separator = "";
	}
	return text.split(separator).reverse().join(separator);
}



JEST

YUI Test

És un entorn de comprovació creat per Yahoo! Proporciona un nombre impressionant de característiques i funcionalitats que garanteixen la cobertura de qualsevol cas de comprovació única. Es distingeix per:

  • Àmplia i exhaustiva funcionalitat
  • És compatible amb la comprovació asincrónica
  • Bona simulació d'esdeveniments.

web : http://yuilibrary.com/projects/yuitest/

JsUnit

És el més antic en termes d'edat de la base de codi i qualitat. Ve del popular entorn de comprovació Java JUnit per Javascript. L'entorn no s'ha actualitzat molt recentment i per això pot ser que no sigui la millor opció per treballar amb els navegadors moderns. web: https://github.com/pivotal/jsunit Existeix una versió que s'està implementant per donar suport als nous navegadors que es diu Jasmine: web: https://github.com/pivotal/jasmine


Les Funcions son fonamentals

Les funcions, en Javascript, són objectes de primera classe, és a dir, coexisteixen amb qualsevol altre objecte i poden tractar-se com un d'ells. Igual que els tipus més mundans de Javascript, les variables poden fer referència a elles, es poden declarar amb literals i fins i tot passar-se com a paràmetres d'altres funcions.

La funció és la principal unitat modular d'execució. Vol dir que excepte els comandos incrustats en el codi que s'executen mentre es avalua les etiquetes, tot la resta de les nostres pàgines està dins d'una funció.


Objectes

La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta :

var obj1 = new Object();
var obj2 = {};

Això crea un objecte nou, buit i que més tard podem ampliar amb propietats:

var o = {};
o.name = "Marta";
o.feina = "contable";
o.antiguitat = 11;

Per eliminar una propietat podem utilitzar l'operador delete:

var obj1 = new Object()
alert(obj1.nombre)   // undefined

obj1.nombre = "mundo"
alert(obj1.nombre)   // "mundo"

delete obj1.nombre

alert(obj1.nombre)   // undefined otra vez

Per afegir un mètode podem fer:

var obj1 = new Object();
obj1.nombre = "mundo";
obj1.saluda = function() { alert("hola "+this.nombre) };
obj1.saluda();

També podem construir objectes de manera literal:

var obj1 = {nombre:"mundo",
            saluda: function() { alert("hola "+this.nombre) }
};
obj1.saluda();

I podem accedir als mètodes i a les propietats de diferents maneres:

var obj1 = new Object();
obj1.nombre = "mundo";
obj1.saluda = function() { alert("hola "+this.nombre) };

alert("hola " + obj1.nombre);       // Acceso normal
alert("hola " + obj1[ "nombre" ]);  // Acceso indexado con un literal
var prop = "nombre";
alert("hola " + obj1[ prop ]);      // Acceso indexado con una variable

obj1.saluda();         // Invocación normal
obj1[ "saluda" ]();    // Acceso indexado con un literal
var func = "saluda";
obj1[ func ]();        // Acceso indexado con una variable

Les funcions com a objectes de primera classe

Els objectes tenen les següents capacitats:

  • Es creen a través de literals.
  • S'assignen a variables, entrades de matriu i propietats d'altres objectes.
  • Es poden passar com a arguments per a funcions.
  • Es retornen com a valors a partir de funcions.
  • Tenen propietats que poden crear-se i assignar-se de forma dinàmica.

Les funcions tenen totes aquestes capacitats, a més tenen la capacitat que poden invocar-se.

Exemple :

var parOimpar = (function() {
    var hoy = new Date()
    if (new Date().getDate() % 2 == 0) {
        return function() { alert("hoy es dia par") }
    } else {
        return function() { alert("hoy es dia impar") }
    }
})()

parOimpar();


Arrow =>

¿Cuántas veces has programado un código con una estructura similar a la siguiente?

// ES5
// Imaginemos una variable data que incluye un array de objectos
var data = [{'nombre':"julio","apellido":"noguera"}, {"nombre":"albert","apellido":"canela"}, {"nombre":"alex","apellido":"salinas"}];

data.forEach(function(i){
 console.log(i);

});

Con la función arrow => de ES6, el código anterior se sustituiría por:

//ES6
var data = [{'nombre':"julio","apellido":"noguera"}, {"nombre":"albert","apellido":"canela"}, {"nombre":"alex","apellido":"salinas"}];

data.forEach(i => console.log(i));

});

Mucho más limpio y claro. CoffeeScript (un metalenguaje que compila a JavaScript) usa algo parecido.

Incluso la podemos utilizar así:

// ES5
var miFuncion = function(num) {
	return num + num;
}

// ES6
var miFuncion = (num) => num + num;

El mètode .map()

La funció map() s'aplica a tots els elements del vector, de maneta similar a forEach():

let noms= ['julio', 'albert', 'alex'];
noms.map(i=> i.length);
})


Altre exemple

var vect = [1,2,3,4,5];
vect.map(function(i){
 return i+5;
})

que retorna: [ 6, 7, 8, 9, 10 ]

El vector inicial no es modifica, ie, map() no és destructiva. Si imprimim el vector de nou:

vect
[ 1, 2, 3, 4, 5 ]


Per tant, no podem modificar el vector directament amb coses com:

var vect = [1,2,3,4,5];
vect.map(function(i){
 i=i+5;
})

que retorna:

[ undefined, undefined, undefined, undefined, undefined ]
vect
[ 1, 2, 3, 4, 5 ]

Però sí podem modificar el vector inicial si li assignem el retorn del mapeig:

var vect = [1,2,3,4,5];
vect = vect.map(function(i){
 return i+5;
})

/*
var vect = [1,2,3,4,5];
vect = vect.map( i =>  i+5);
*/

que retorna:

[ 6, 7, 8, 9, 10 ]

però ara vect val:

[ 6, 7, 8, 9, 10 ]

El mètode .reduce()</span>

És una funció de reducció que s'aplica a tots els elements del vector, però de dos en dos (o més). Exemple:

var vect = [1,2,3,4,5];

vect.reduce(function(acumulador,incremento){
	console.log(acumulador+" "+incremento+" "+(acumulador+incremento));
 return acumulador+incremento;
})

que retorna la suma de tots els elements:

15

Exercici

Els arrays en Javascript no tenen un mètode que ens retorni el màxim. Usa el mètode reduce per a obtenir el màxim d'un array de nombres.

Solució:

var vect = [3,25,99,16,80,12,20];

var major=vect.reduce((a,b)=>{if(a<b) return b;else return a;});	

document.write("<br>"+typeof major+" "+ major);

El mètode .filter()

És una funció que s'aplica a tots els elements del vector, i només retorna aquells que compleixen la condició. Exemple:

var vect = [1,2,3,4,5];
var resul=vect.filter(function(i){
 if(i>3)
   return i;
})

let resul=posts.filter(i=>i>3);  //en resul un array de los números mayores de 3

/*const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);
 //devuelve Array ["exuberant", "destruction", "present"]


*/

que retorna:

resul=[ 4, 5 ]

Exercici filter

Crea un programa que a partir d'un array de 10 números, obtingui dos arrays anomenats parells i senars amb els números parells i senars respectivament de l'array inicial. Usa el mètode filter.

map, arrow,filter, reduce, findIndex

Dado un objeto

posts = [ 
  {id: 1, upVotes: 2},
  {id: 2, upVotes: 18}, 
  {id: 3, upVotes: 1}, 
  {id: 4, upVotes: 30}, 
  {id: 5, upVotes: 50} 
];

Se desea hacer un benchmark para comprobar la velocidad de " for, foreach, map, filter, reduce..." por tanto se usará console.time('ejemplo') para establecer el tiempo de inicio y console.timeEnd('ejemplo') para finalizar el cronómetro.


Plantillas literales

let a = 5;
let b = 10;

console.log('Quince es ' + (a + b) + ' y\nno ' + (2 * a + b) + '.');

// "Quince es 15 y
// no 20.
let a = 5;
let b = 10;

console.log(`Quince es ${a + b} y
no ${2 * a + b}.`);

// "Quince es 15 y
// no 20."


Àmbit de les variables

L'àmbit d'una variable (anomenat "scope" en anglès) és la zona del programa en la qual es defineix la variable. JavaScript defineix dos àmbits per a les variables: global i local.

El següent exemple il·lustra el comportament dels àmbits:

function creaMensaje () {
var missatge = "Missatge de prova"; 
} 
creaMensaje (); 
alert (missatge);

L'exemple anterior defineix en primer lloc una funció anomenada creaMensaje que cregui una variable anomenada missatge. A continuació, s'executa la funció mitjançant l'anomenada creaMensaje (); i tot seguit, es mostra mitjançant la funció alert () el valor de una variable anomenada missatge.

No obstant això, en executar el codi anterior no mostra cap missatge per pantalla. La raó és que la variable missatge s'ha definit dins de la funció creaMensaje () i per tant, és una variable local que només està definida dins de la funció.

Qualsevol instrucció que es trobi dins de la funció pot fer ús d'aquesta variable, però totes les instruccions que es trobin en altres funcions o fora de qualsevol funció no tindran definida la variable missatge. D'aquesta manera, per mostrar el missatge en el codi anterior, la funció alert () ha de cridar des de dins de la funció creaMensaje ():

function creaMensaje () {
var missatge = "Missatge de prova"; 
alert (missatge);
}

Què passa si una funció defineix una variable local amb el mateix nom que una variable global que ja existeix? En aquest cas, les variables locals prevalen sobre les globals, però només dins de la funció:

var missatge = "guanya la de fora"; 

function muestraMensaje () {
var missatge = "guanya la de dins"; 
alert (missatge); 
} 

alert (missatge); 
muestraMensaje (); 
alert (missatge);

El codi anterior mostra per pantalla els següents missatges:

guanya la de fora 
guanya la de dins 
guanya la de fora

Dins de la funció, la variable local anomenada missatge té més prioritat que la variable global del mateix nom, però només dins de la funció. Què passa si dins d'una funció es defineix una variable global amb el mateix nom que una altra variable global que ja existeix? En aquest altre cas, la variable global definida dins de la funció simplement modifica el valor de la variable global definida anteriorment:

var missatge = "guanya la de fora"; 

function muestraMensaje () {
missatge = "guanya la de dins"; 
alert (missatge); 
} 

alert (missatge); 
muestraMensaje (); 
alert (missatge);

En aquest cas, els missatges mostrats són:

guanya la de fora 
guanya la de dins 
guanya la de dins

La recomanació general és definir com a variables locals totes les variables que siguin d'ús exclusiu per a realitzar les tasques encomanades a cada funció. les variables globals s'utilitzen per compartir variables entre funcions de forma senzilla.

Més exemples

//Global- Podemos accedes a ellas desde cualquier parte del cogido 
 //Local - Variables creadas dentro de una función solo pueden ser accedidas, desde su función o una función anidada

 	var variableGlobal = "variable Global";

      	var miFuncion = function () {
      		var variableLocal = "variable Local";

      		var funcionLocal = function () {
      			var variableLocal = "esta variable es local, dentro de funcionLocal";
      			alert(variableLocal);

      		};

      		funcionLocal();

      		alert(variableLocal);  //variable Local
      	}

      	miFuncion();

      	alert(variableLocal);   //falla


Var vs Let

JAVA

public static void main(String[] args) {
    int a = 1;
    int b = 2;
    
    {
        int c = 3;
    }

    System.out.println(a +" "+ b +" "+ c);
    // Error de compilación: c cannot be resolved to a variable 
}


JAVASCRIPT

var a = 1;
var b = 2;

{
    var c = 3;
}

console.info(a, b, c); // 1 2 3


LET

let a = 1;
let b = 2;

{
    let c = 3;
}

console.info(a, b, c); // ReferenceError: c is not defined

VAR

En resumen, en ES5 (Javascript más tradicional) no se permitía declarar un alcance más acotado, como las llaves de una condición if, un bucle etc.

var permite declarar una variable que sea accesible por todos los lugares de la función donde ha sido declarada. Si una variable con var se declara fuera de cualquier función, el ámbito de esta son todas las funciones del código.

Veamos un ejemplo:

function miFuncion() {

  console.log(miVar);   //undefined
  if (true) {
    var miVar = "Hola mundo";
  }
  console.log(miVar);  //Hola mundo
};

En este caso, pensando en ES5, la variable "miVar" está definida dentro de un bloque if, pero aun así su ámbito será el de la función miFuncion().

LET

Para solucionar todo esto en Javascript ES6 se ha implementado alguna forma nueva de declarar variables que ahora será la más indicada en la mayoría de los casos.

let permite declarar una variable que sea accesible únicamente dentro del bloque donde se ha declarado (llamamos bloque al espacio delimitado por { })

Se trata de la construcción "let" que veremos mejor con un ejemplo similar:

function () {
  console.log(miVar);   //undefined
  if (true) {
    let miVar = "Hola mundo";
  }
  console.log(miVar);   //undefined
};

La clave de let es que restringe su existencia al ámbito donde ha sido declarada (cualquier ámbito expresado con unas llaves).

VARIABLES SIN DECLARAR

Javascript nos permite usar variables no declaradas. Si hacemos esto, será equivalente a declararlas con var fuera del código, es decir, serán variables accesibles por cualquier función.

function ejemplo() {
      ejemplo = 3; // Equivale a declararla fuera de la funcion como var
      if (ejemplo === 3) {
        var variable1 = 1;
        let variable2 = 2;
      }

        console.log(variable1); // variable1 existe en este lugar
     // console.log(variable2); // variable2 no existe en este lugar
    }

    ejemplo();

    console.log(ejemplo);

Invocacions

Hi ha quatre maneres diferents per invocar a una funció, cadascuna amb les seves peculiaritats.

  • 1. Com una funció, en la qual aquesta s'invoca de manera senzilla.
  • 2. Com un mètode, que vincula la invocació a un objecte, habilitant la programació orientada a objectes.
  • 3. Com un constructor, en el qual un nou objecte es fa realitat.
  • 4. A través dels seus mètodes apply() o bé call()

Dels arguments als paràmetres de les funcions

Si el nombre d'arguments i paràmetres és diferent, no hi ha error:

  • Si hi ha mes arguments que paràmetres, els arguments de sobres no s'assignen als noms de paràmetres.
function qualsevol(a,b,c){}
qualsevol(1,2,3,4,5,6); //4,5,6 no s'assignen a cap paràmetre.
  • Si hi ha mes paràmetres que arguments, els paràmetres que no tinguin el seu argument corresponent s'estableixen com undefined
function qualsevol(a,b,c){}
qualsevol(1); //b,c tenen el valor undefined

En totes les invocacions de les funcions es passen 2 paràmetres implícits (es passen en silenci i estan en el seu àmbit) : arguments i this.

  • Arguments

Arguments és una col·lecció de tots els arguments que s'han passat a la funció. Té una propietat length que conté el numero de paràmetres que s'han passat. Els valors dels paràmetres es pot obtenir com en un array. Exemple: arguments[2] ens dóna el tercer paràmetre.

  • This

És el context de la funció. En JAVA this és la instància de la classe en la qual es defineix el mètode. En Javascript no et confiïs. El paràmetre this no es defineix, com en Java, per com es declara la funció, sinó per com s'invoca.

Invocació com una funció

És la manera normal d'invocar a una funció en qualsevol llenguatge. Exemple:

function cridam(){};
cridam();
var unaltre = function(){};
unaltre();

Quan ho fem d'aquesta manera el contexte de la funció és el global. Aixó vol dir que la funció és una propietat del objecte window. Però donem per implícit aquest objecte en la seva crida. Realment, aquesta manera és la mateixa que la invocació com a mètode, ja que aquestes funcions són mètodes de l'objecte window.

Invocació com un mètode

http://www.etnassoft.com/2012/01/12/el-valor-de-this-en-javascript-como-manejarlo-correctamente/

Es produeix quan s'assigna una funció a la propietat d'un objecte. Exemple:

//es crea l'objecte anomenat 'o' 
var o = {};
o.nom_metode = funtion(){};
//es defineix una propietat anomenada 'nom_metode' i se li assigna una funció.
//aquesta propietat la hem convertit en un mètode.

o.nom_metode(); //crida al mètode.

Quan invoquem d'aquesta manera a la funció, l'objecte es converteix en el contexte de la funció, es a dir, el paràmetre implícit this correspon al objecte.


Què és exactament this

La paraula clau this té en Javascript un comportament diferent al d'altres llenguatges però en general, el seu valor fa referència al propietari de la funció que l'està invocant.

La paraula clau del paràgraf anterior és "propietari".

Quan no estem dins d'una estructura definida, això és un objecte amb mètodes, el propietari d'una funció és sempre el context global. En el cas dels navegadors web, hem de recordar que aquest objecte és window:

console.log( this === window );  // true
 
function test(){
  console.log( this === window);
}
 
test(); // true


Accedint als valors d'un objecte des del propi objecte

Aquest concepte de propietari pot induir a errors. Pensem en un objecte amb una sèrie de propietats:

var myApp = {
  name : 'Megan',
  lastName : 'Fox',
  birthDate : '16/05/1986',
  isPretty : true
};
 
console.log( myApp.name ); // Megan
console.log( myApp.isPretty ); // true

Suposem ara que necessitem una altra propietat més 'dinàmica' que participi dels valors assignats a qualsevol altra. Per exemple, volem un 'completeName "que concatene' name 'i' lastname '. Sembla que aquest un clar exemple d'ús per a this:


var myApp = {
  name : 'Megan',
  lastName : 'Fox',
  completeName : this.name + this.lastName
}

Encara que sembla coherent, quan passem a comprovar-ho veiem que el resultat no és l'esperat:

console.log (myApp.completeName); // undefined

El problema aquí és que dins d'aquest no està apuntant a l'objecte com es podria esperar, sinó que està buscant la referència fora, en el context global (finestra).

Per obtenir el resultat esperat hem d'aplicar un patró d'invocació que modifiqui al propietari des del qual s'invoca el this ...



Patró d'invocació per mètode


En el desenvolupament d'aplicacions modernes, el patró més recurrent és el d'invocació per mètode: una funció és emmagatzemada com a propietat d'un objecte convertint-se així en el que anomenem un mètode.

Quan diem (invoquem) a un mètode, this fa refencia al mateix objecte:

var myApp = {
  name : 'Megan',
  lastName : 'Fox',
  completeName : function(){
    return this.name + ' ' + this.lastName;
  }
}
 
console.log( myApp.completeName() ); // Megan Fox


En aquesta ocasió, si podem comprovar com this apunta al mateix objecte i busca la propietats 'name' i 'lastname' dins en lloc de remuntar-se fins el context global.

Exercici 7

¿Quin és el seu valor?

var myApp = function(){
  var name = "World"
  var sayHello = function(){
    console.log( 'Hello, ' + this.name );
  };
  sayHello(); 
};
 
myApp();


Aquest comportament el podem comprovar si creem una variable global amb aquell nom pel qual estem preguntant ¿Quin és el seu valor?

var name = "Strange World";      //la variable pertenece a window
var myApp = function(){
  var name = "World"             
  var sayHello = function(){
    console.log( 'Hello, ' + this.name );       //this pertenece a window
  };
 
  sayHello();
 
};
 
myApp();

La conseqüència d'aquest error és que un mètode no pot utilitzar funcions internes que l'ajudin a fer la seva feina perquè aquestes, no té accés a les seves propietats.

Exercici 7.1

Mostra amb un framework unitari qui és l'objecte del argument this en cada cas:

function unica(){return this;};

var replica = unica;

var objecte1 = {
 clon : unica
}

var objecte2 = {
 clon : unica
}

solució S'ha d'observar que el contexte canvia depenent de com s'invoca la funció. Pensa que la funció és la mateixa en tots els casos. Objecte1 i Objecte2 comparteixen la mateixa instància de la funció, fins i tot quan s'executa, la funció té accés al objecte que va invocar el mètode i pot realitzar operacions amb ell. Aquest és el principi de la programació orientada a objectes.

Exercici 8
var persona = {
    name: 'edu',
    twitter: 'eiximenis',
    twitterUrl: 'http://twitter.com/' + this.twitter
};
 
console.log(persona.twitterUrl);


Exercici 8.1

console.log(this);

function test(){
	
console.log(this);
}

test();

Exercici 8.2

var obj = {
	name: 'obj',
	run: function(){
		
		this.value = 1;
		console.debug(this.name);
	}
};

obj.run();

Exercici 8.3

var obj = {
	name: 'obj',
	run: function(){
		this.value = 1;
		console.debug(this); 
		
		(function(){ // se crea un nuevo scope
			console.debug(this); 
		})();
		
		function test(){ // se crea un nuevo scope
			console.debug(this);
		}
		
		test();
	}
};

obj.run();

Exercici 8.3.1

var obj = {
                name: 'obj',
                run: function () {
                    this.value = 1;
                    console.log(this);

                    (function () { // se crea un nuevo scope
                        console.log(this);
                    })();
                    that=this;
                    
                    function test(t) { // se crea un nuevo scope
                        console.log(t);
                    }

                    test(that);
                }
            };

            obj.run();

Exercici 8.4

var obj = {
    name: 'obj',
    run: function(){
        this.value = 1;
        console.debug(this); 
         
        (function(){
            console.debug(this); 
        }).call(this); // se autoejecuta con el método call
         
        this.test = function(){ 
            console.debug(this); 
        }
         
        this.test(); 
    }
};
 
obj.run();

Exercici 9

Digues que es mostrarà a cada alert. Explica-ho.

var missatge2 = "hola"

function Nova (){
	var missatge2 = "adeu";
	this.missatge2 = "hello";
	alert("Missatge2 local: " + missatge2 + " ; Missatge2 global: " + this.missatge2);
}

var e = new Nova();
alert(e.missatge2);
alert("window : " + missatge2);


Invocació com constructor

Per invocar una funció com a constructor no té cap misteri. S'ha de posar la paraula new davant de la funció. El que té de interessant és el que passa quan ho fem:

  • Es crea un objecte buit.
  • Aquest objecte es passa al constructor com paràmetre this i d'aquesta manera es converteix en el contexte de la funció.
  • En absència de qualsevol valor retornat de forma explícita, el nou objecte es retorna com a valor del constructor.

Que passaria si invoquem a la funció sense utilitzar la paraula new?

  • doncs que no es crea l'objecte i, llavors, les propietats i mètodes que pugui haver pertanyen al objecte window.

Com sabem si una funció s'utilitza per crear objectes o son funcions normals?

  • Doncs no hi ha una manera estàndard
  • Per convenció si les funcions creen objectes llavors el nom de la funció comença amb lletra MAJÚSCULA.
function Cotxe(){
 this.matricula = "";
}

/*cridem a la funció d'aquesta manera:*/
var cotxe1 = new Cotxe();

En aquest exemple, la propietat matricula pertany a l'objecte cotxe1. Si no haguéssim posat la paraula new el paràmetre this que s'utilitza dintre de la funció faria referència al objecte window. Com s'ha posat la paraula new el paràmetre this fa referència al nou objecte creat.

Invocació amb els mètodes apply() i call()

Javascript ens proporciona un mitjà per invocar a una funció i especificar de forma explícita qualsevol objecte que vulguem com a context. És a dir, podem decidir quin és el valor del paràmetre this quan cridem a una funció. S'aconsegueix amb qualsevol dels dos mètodes que posseeixen les funcions: apply() i call(). Sí, totes les funciones tenen dos mètodes disponibles, ja que son objectes de primera classe poden tindre propietats i mètodes igual que qualsevol altre objecte. Paràmetres del mètode apply():

  • L'objecte que s'utilitzarà com a context de la funció
  • Array de valors que s'utilitzaran com a arguments de la funció.

Paràmetres del mètode call():

  • L'objecte que s'utilitzarà com a context de la funció
  • Llistat de valors que s'utilitzaran com a arguments de la funció.

Exemple:

function exemple(){
   var result = 0;
   for (var i = 0; i < arguments.length; i++){
        result += arguments[i];
   }
   
   this.result = result;
}

var objecte1 = {};
var objecte2 = {};

exemple.apply(objecte1,[1,2,3,4]);
exemple.call(objecte2,5,6,7,8);

// en aquest punt objecte1.result tindrà el valor 10
// i objecte2.result tindrà el valor 26

Les funcions sense nom

Les funcions sense nom s'utilitzen quan volem utilitzar-les posteriorment. Exemples:

  • quan les emmagatzemem en una variable,
  • quan les posem com a mètodes d'objectes
  • quan les utilitzem com devolució de trucada (callback de timeout, callback de controladors d'events, etc).
window.onload = function () {assert(true, "2");};


var obj = { 
            print : function () {assert(true, "1");} 
          }
obj.print();


setTimeout(function(){ assert(true, "3"); }, 500);

L'ordre de sortida per pantalla és el següent : 1,2,3 També podíem haber fet el següent amb el controlador de l'event càrrega de pàgina:

function bootMeUp(){
     assert(true, "2");
};

window.onload = bootMeUp;

Però, per qué donar-li nom si mai més la cridarem? Realment necessitem que bootMeUp sigui un mètode del objecte window? A més a més, podem pensar que el mètode print és el nom de la funció anónima que l'assignem. NO!!. Demostra-ho utilitzant la propietat name de les funcions.

Funcions amb noms en linia

Però que succeeix si posem nom a les funcions sense nom? Exemple:

var persona = {
   cantar : function xiular(n){...}
}

La funció xiular no la podem cridar fora de la funció. Peró sí la podem crear dintre, es a dir, ens interesa posar nom a les funcions sense nom quan les volem fer recursives.

var persona = {
   cantar : function xiular(n){ return n > 1 ? xiular(n-1) + "-fiu" : "fiu"; }
}


Paràmetres ...REST

Els paràmetres REST són un conjunt de paràmetres que s'emmagatzemen com array en un "paràmetre final" nomenclado amb ... nombreParametro. Això ens permet gestionar la funció sense haver de controlar el nombre de paràmetres amb els quals aquesta és cridada. Important: només l'últim paràmetre pot ser REST.

function miFuncion(a, b, ...masArgumentos) {
  console.log("a", a); 
  console.log("b", b);
  console.log("masArgumentos", masArgumentos); 
  console.log("four", masArgumentos[1]); 
}

miFuncion("one", "two", "three", "four", "five", "six");

// Console Output:
// a, one
// b, two
// manyMoreArgs, [three, four, five, six]
// four, four


Sobrecàrrega de funcions

En altres llenguatges de programació orientats a objectes, per sobrecarregar una funció se sol declarar distintes implementacions de mètodes amb el mateix nombre però amb un conjunt diferent de paràmetres. En Javascript no es fa d'aquesta manera. En Javascript es sobrecarreguen les funcions amb una única implementació que modifica el seu comportament mitjançant l'exàmen del nombre d'arguments que l'han proporcionat.

És fàcil d'imaginar que es podria implementar la sobrecàrrega de funcions utilitzant una estructura del tipus if-then i else-if. Però no sempre ho podrem fer.

Exemple: Funciò sobrecarregada de manera monolítica:

var persona = {
        calculMatricula = function(){
	  	switch(arguments.length){
			case 0:
				// fer algo
				break;
			case 1: 
				// fer una altre cosa
				break;
			case 2:
				// fer una altre cosa més
				break;
			... etc ...		
		}
	}
}

Sin pasar argumentos

function suma(){


switch(arguments.length){
			case 0:
				console.log("cero");
				break;
			case 1: 

				console.log(arguments[0]);
				break;
			case 2:
			   console.log(arguments[0]+arguments[1]);
				break;
			
		}
}


suma();
suma(2);
suma(3,4)

SOLUCIÓ

Tenemos un array con una serie de nombre y apellidos ["joan garcia", "jaume pontons", "ana riu", "marta aran", "alex fornell", "mariona cots"], en caso de no pasar ningún argumento devolverá el array, si pasamos un trozo de cadena y lo encuentra, deberá añadirlo en un nuevo array y devolverlo, en caso de pasar 2 parámetros (nom, apellidos) deberá encontrarlos e introducirlos en el nuevo array.


Veurem una tècnica per ens permet crear diverses funcions (aparentment amb el mateix nom, però es diferència pel número de paràmetres) que poden escriure's com diferents, anónimes e independents i no com un bloc monolític if-then-else-if. Tot aixó depén de una propietat poc coneguda de les funcions : la propietat length.

length de funció

El paràmetre length de funció no ha de confondre's amb la propietat length del paràmetre arguments. El paràmetre length de funció ens indica el número total de paràmetres formals amb els que s'ha declarat la funció. La propietat length del paràmetre arguments ens indica el número total de parámetres que s'han passat a la funció en el moment de cridar-la.

Exemple:

function max(a,b){
   ...
}

max(1,4,5,7,23,234);

En aquest cas el paràmetre length de la funció max és 2 i la propietat length del paràmetre arguments és 6.

Utilitzarem aquest paràmetre per crear funcions sobrecarregades.

function afegirMetode(objecte, nom, funcio){
	var old = objecte[nom];
	objecte[nom] = function(){
				if(funcio.length == arguments.length)	
					return funcio.apply(this, arguments);
				else if (typeof old == 'function')
					return old.apply(this, arguments);
		};
}


var persona = {};
afegirMetode(persona, "calculMatricula", function(){ fer algo  });
afegirMetode(persona, "calculMatricula", function(a){ fer una altre cosa  });
afegirMetode(persona, "calculMatricula", function(a,b){  fer una altre cosa més  });

Exercici 9 : Sobrecàrrega de funcions

Donat el següent objecte:

var usuaris = {
       noms : ["joan garcia", "jaume pontons", "ana riu", "marta aran", "alex fornell", "mariona cots"]
	};

Crea una funció anomenada trobar que segons el número de paràmetres faci ;

  • Si no es pasa cap paràmetre : Retorni directament l'array de noms.
  • Si es pasa 1 paràmetre : Retorni de la llista de noms aquells noms que comencin per la cadena pasada com a únic argument.
  • Si es pasen 2 paràmetres : Retorni de la llista de noms aquells noms que el nom sigui el primer paràmetre i el cognom el segon.

SOLUCIÓ Exercici 9.1 Sobrecarga

Escrigui un programa que calculi diverses operacions, en cas de passar-li dos numeros han de tornar la divisió entre tots dos (No pot ser divisible per 0), en cas de passar-li tres paràmetres ha de tornar els dos valors d'una equació de segon grau.

Exercici 9.2 Sobrecarga

Escrigui un programa que calculi el àrea de diferents figures geomètriques (triangle, quadrat, rectangle, cercle, trapezi, etc.) sobrecarregant la funció àrea amb el número i tipus de arguments necessaris per cada tipus de figura.

Clausures

https://medium.com/@sergiodxa/definiendo-conceptos-closure-y-scope-en-javascript-9081f1e113e6 Una clausura és l'àmbit que es crea quan es declara una funció i es permet que aquesta pugui accedir i manipuli variables externes a ella, és a dir, són variables locals d'una funció mantingudes vives després que la funció hagi retornat Exemple:

var missatge = "hola";
function accedirValor(){
	alert(missatge);
}

De moment, sense sorpreses. La funció accedirValor pot accedir al valor de la variable externa missatge. Aquesta variables i aquesta funció estàn definides en l'àmbit global i aquest àmbit sempre existirà mentre duri el programa. Però que pasaria si... :

var missatge = "hola";
var despres;

function accedirValor(){
	var missatge_intern = "adeu";
	function accedirValorInternExtern(){
		alert("extern: " +  missatge);        //les variables es mantenen vives 
		alert("intern: " +missatge_intern);   
	}
	despres = accedirValorInternExtern;        //es igual a accedirValorInterneExtern();
}

accedirValor();
despres();

Conclusió:

  • accedirValor funciona correctament. Están definits en l'ambit global i per tant pot accedir sempre a les variables.
  • despres()...no funciona com pensàvem, oi? La variable missatge_intern està viva! Per què? per les clausures.

Quan declarem la funció accedirValorInternExtern dintre de la funció accedirValor, no estem només declarant la funció si no que estem creant una clausura que la envolta a ella i a les variables que estan en el seu àmbit en el moment de la declaració.

Podem imaginar una clausura com una bombolla segura de la funció. Les variables que estan dintre del àmbit de la funció en la seva declaració i la mateixa funció estan dintre d'aquesta bombolla. Així aquesta funció disposa de tots els elements necessaris per poder-se executar.

Anem a ampliar aquest concepte. Mireu la modificació que faig del codi anterior:

var missatge = "hola";
var despres;

function accedirValor(){
	var missatge_intern = "adeu";
	function accedirValorInternExtern(salutacio){
		alert("extern: " +  missatge);
		alert("intern: " + missatge_intern);
		alert("salutacio " + salutacio);
		alert("fin " + fin);
	}
	despres = accedirValorInternExtern;
}

alert("mintern" + missatge_intern);
alert(fin); 
var fin = "tard";
accedirValor();
despres("fins despres");

Aquí estas creando una clausura. La creas en el momento que declaras una función dentro otra. Y permanecerá viva mientras viva la función declarada internamente.

Conclusió: la funció interna pot veure totes les variables que hi ha en aquest codi. Però com es aixó?

Conceptes relacionats amb les clausures

  • Els paràmetres de la funció s'inclouen en la clausura d'aquesta funció.
  • Totes les variables del àmbit extern, incloent les que es declaren després de la declaració de la funció, estan incloses.
  • Dintre del mateix àmbit, les varibles que encara no s'han definit no poden ser referenciades més endavant.

Més Exemples de Clausures

Supone el siguiente código, el ejemplo mas simple que se me ocurre.

function saltos(valor) {
  var acumulado = 0;
  return function() {
    acumulado += valor; 
    return acumulado;   
  };
}

Aquí estas creando una clausura. La creas en el momento que declaras una función dentro otra. Y permanecerá viva mientras viva la función declarada internamente.

var quintos = saltos(5);
quintos(); // retorna 5
quintos(); // retorna 10
quintos(); // retorna 15
// y asi sigue... 20, 25, 30..

En definitiva, incluso después de que termina la ejecución de saltos(5), JavaScript mantiene una referencia a las variables declaradas en saltos (acumulado y valor), visibles para la función creada en el interior.


Utilitzar les clausures per crear variables privades

És un ús molt comú utilitzar les clausures per definir les variables privades. De fet, ja ho has estat fent. Exemple:

function Persona(){
	var anys = 0;
	this.getAnys = function(){
		return anys;
	};
	this.envellir = function(){
		anys++;
	};
}

var joan = new Persona();
joan.envellir();

alert("no podem accedir: " + joan.anys);
alert("getanys: " + joan.getAnys());


Les clausures es diuen així perquè en realitat el que representen és a funcions que tenen accés a una sèrie de variables, lliures del seu propi àmbit (estan en un àmbit superior), i que fan ús d'elles mitjançant una sintaxi externa que és la que les estableix i li dóna el sentit (les tanca o clausura, d'aquí el nom).

Es veurà millor amb un exercici més apropiat com el següent codi JavaScript:

Exercici 1. Digues que mostra.

function concatenar(s1) {
      return function(s2) {
        return s1 + ' ' + s2;
      };
}

var diHola = concatenar("Hola");

alert( diHola("visitante") );


És a dir, en la pràctica gràcies a l'ús d'una clausura hem definit una funció que permet assignar valors per a execució retardada. Això és una cosa realment útil, i no és l'única aplicació pràctica de les clausures, però gràcies a això podem habilitar tot un sistema d'execució en diferit de funcions JavaScript. Això ens permet crear punters a funcions pre-parametritzades i amb això crear un sistema d'esdeveniments, llançar accions periòdiques complexes i particularitzades amb setInterval o setTimeout ... i moltes altres coses.

Exercici 2. Digues que mostra.

function dirHola2(nom) {
 var texto = 'Hola ' + nom; // local variable
 var dirAlerta= function() { alert(texto); }
 return dirAlerta;
}

var dir2=dirHola2('Joan');

dir2();


Exercici 3. Digues que mostra.

function dir666() {
 // Variable local que acaba en la clausura
 var num = 666;
 var dirAlerta= function() { alert(num); }
 num++;
 return dirAlerta;
}


var dirNombre=dir666();

dirNombre();


Exercici 4. Digues que mostra.

var unicId = (function() { 
  var comptador = 0; 
  return function() { 
    return "únic-id-" + comptador++; 
  }; 
})(); // Funció que s'auto-invoca i executa automàticament  
 

unicId(); 

unicId(); 

unicId();

Exercici 5. Digues que mostra.

var crearContador = function () {
                var cuenta, f;
                cuenta = 0;
                f = function () {
                    cuenta = cuenta + 1;
                    return cuenta;
                };
                return f;
            };
            var contador = crearContador();
            /* contador es una funcion que no recibe argumentos
             y retorna una cuenta */

            var a = contador();
            console.log(a);
            var b = contador();
            console.log(b);
            var c = contador();
            console.log(c);

            var contador2 = crearContador(); // crear otro mas
            var d = contador2();
            console.log(d);
            var e = contador2();
            console.log(e);
            var f = contador2();
            console.log(f);

Una cosa útil que les clausures poden fer és guardar l'estat intern. Recorda que una clausura és creada quan una funció interna referència a una variable de la funció externa.

En aquest exemple, cada invocació d'crearContador crea un nou abast("alcance") de compte, i la clausura circumdant a la funció interna f captura aquest abast.


http://www.variablenotfound.com/2012/10/closures-en-javascript-entiendelos-de.html Enllaç Complementari

Funcions anònimes, autoexecutables i que retornen funcions

Tracta d'evitar utilitzar variables globals, per temes de securetat. Per exemple, una variable global llistaUsuaris.

Una funció anònima es pot definir sense que sigui asiganada a cap variable:

function(qui) {

    alert("hola "+qui)

}

No obstant això, fer això és completament inútil: definir una funció sense nom fa que sigui impossible ser executada més tard, ja que sense un nom amb el qual accedir-hi és impossible trobar-la. Però podem executar-la en el mateix moment en què la definim. Per fer-ho, només hem de tancar entre parèntesis, i després utilitzar uns nous parèntesi amb els paràmetres, com fem amb una funció normal.

(function() { alert("hola món") })()

Per descomptat, podem passar-li paràmetres a la nostra funció autoexecutable. En el següent exemple, es passa com a paràmetre "món" a la funció:

(function(qui) {

    alert("hola "+qui)

})("món")

Pot semblar poc útil fer això ara, però més endavant veurem com és una fantàstica manera d'arreglar certs problemes.

Per descomptat, una funció pot retornar una funció anònima. Serà responsabilitat del programador assignar-la a una variable:

function saludator(qui) {
    return function() {
        alert("hola "+qui)
    }
}

var saluda = saludator("món")
saluda()

podem executar la funció que s'ha retornat directament, sense assignar-la a cap variable:

function saludator(qui) {
    return function() {
        alert("hola "+qui)
    }
}

saludator("món")()

És clar, ningú et impedeix sobreescriure una funció amb una altra.

function saludator(qui) {

    return function() {

        alert("hola "+qui)

    }

}

 

saludator = saludator("món")

saludator()

Aquí, la primera vegada que executem saludator ("món") ens retorna una funció anònima (que mostra "hola món"). Aquesta funció és assignada a la variable saludator, de manera que la segona vegada que truquem saludator (), estem executant la nova funció anònima (la del "hola món"), i la funció inicial original es perd per sempre.

Funcions immediates

Una Funció immediata es basa en el concepte de les clausures. Exemple de funció immediata:

(function(){})()

Analitzarem la construcció de la funció ignorant el primer grup de paréntesis.

(....)()

Sabem que podem fer la crida d'una funció utilitzant la sintaxis functionName(), però en lloc del nom podem utilitzar qualsevol expressió que es refereixi a una de les seves instàncies.

var algunaFuncio = function(){...};
result = algunaFuncio();
// o també podem fer:
result = (algunaFuncio)();

Aixó significa que (---)(), el primer joc de parèntesis és un delimitador que tanca una expressió. El segon lloc de paréntesis és un operador.

Ara en lloc d'una variable, posem la funció anónima directament.

(function(){...})();

Que fa aquesta funció?

  • Crea una instància de la funció
  • Executa la funció
  • Descarta la funció

Per què és útil? Podem crear un àmbit temporal que emmagatzemi el nostre estat.

(function(){
	var numclicks = 0;
	document.addEventListener("click", function(){alert(++numclicks);}, false);
})();

Lo important és observar que es crea una clausura pel controlador que inclou numclicks, llavors només ell pot fer referència a aquesta variable. Ningú més podrá modificar el seu valor. Aquesta és una de les formes d'ús comú de les funcions immediates: com envoltoris simples e independents.

Es poden passar paràmetres a les funcions immediates? Exemple:

(function(salutacio){alert(salutacio);})("Hola");

Les funcions aniuades

Les funcions que es troben dintre de altres funcions s'anomenen internes perque només podem accedir a elles dintre del codi de la funció que la engloba. A aquesta estructura l'anomenen funcions niades. Exemple:

function saluda(quien) {
    function alertasaludo(quien) {
        alert("hola "+quien)
    }
    alertasaludo(quien)

}
saluda("mundo")

Podem combinar funcions niades amb funcions que retornen funcions:

function saludator(quien) {
    function alertasaludo() {
        alert("hola "+quien)
    }

    return alertasaludo
}

var saluda = saludator("mundo")
saluda()

I lo anterior ho podem combinar amb funcions anónimes i auto-executables:

var saluda = (function(quien) {
    function alertasaludo() {
        alert("hola "+quien)
    }

    return alertasaludo
})("mundo")

saluda();

Exemple del seu ús:

var parOimpar = (function() {
    var hoy = new Date()
    if (new Date().getDate() % 2 == 0) {
        return function() { alert("hoy es dia par") }
    } else {
        return function() { alert("hoy es dia impar") }
    }
})()

parOimpar();
function funcion1(){   

	let funcion1 ="funcion1";
			
				function funcion2(){

				let funcion2="funcion2";

						function funcion3(){

							return "Solución";
								               
						}

				                return funcion3;
					         
				}

			       return funcion2;
	}


var resultado1=	funcion1();
var resultado2= resultado1();
var resultado=	resultado2();

var otraForma= funcion1()()();

Exercicis

Exercici YAHOO

Els Yahoo compten amb els dits : un, dos, tres i quatre. Coneixen el cero, però no les quantitats negatives, per a ells son quantitats desconegudes. Conscients de la seva ignorància, sospiten de la existència de una quantitat més gran que quatre: molts.

a) Funció següent :

Per poder comptar, els Yahoo coneixen la operació següent que transforma una quantitat en una altre de la següent manera :

– El següent de lo desconegut continua sent desconegut

– Per a les altres quantitats de zero a quatre, el següent és de un a molts respectivament.

– Per últim, el següent a molts és també molts.

Crea el mètode següent de la classe Yahoo :

Function Yahoo(){

     var numeros = ....

     this.seguent = function(numero){....}

     }

// utilització del mètode:

var yahoo1 = new Yahoo();

alert(yahoo1.seguent(“desconegut”)); // ha de mostrar l'alert : 'desconegut'

alert(yahoo1.seguent(“cero”)); // ha de mostrar l'alert : 'un'

alert(yahoo1.seguent(“quatre”)); // ha de mostrar l'alert : 'molts'

alert(yahoo1.seguent(“molts”)); // ha de mostrar l'alert : 'molts'

b) Funció suma :

Els Yahoos tenen un mètode suma que funciona de la següent manera:

– suma(): retorna el valor desconegut

– suma(x): retorna el valor x (x pot ser zero, un, dos, tres, quatre, molts o desconegut)

– suma(numero, x)

 si numero és desconegut, retorna desconegut sigui quin sigui x

 si numero és zero, retorna lo mateix que suma(x)

 si numero és u, retorna seguent(x)

 si numero és dos, retorna seguent(seguent(x))

 .....

 si numero és molts, retorna molts sigui quin sigui x.



Bibliografia

John Resig, Bear Bibeault, "Secrets of the Javascript Ninja", Manning Publications, 2012. ISBN 193398869X

albertovilches

msdn-firefox