IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Created by Netscape in 1995 as an extension of HTML for Netscape Navigator 2.0, JavaScript had as its main function the manipulation of HTML documents and form validation. Before winning this name so famous nowadays, JavaScript was called Mocha. When it first shipped in beta releases, it was officially called LiveScript' and finally, when it was released by Sun Microsystems, was baptized with the name by which it is known today. Because of the similar names, people confuse JavaScript with Java. Although both have the lexical structure of programming, they are not the same language. Different from C, C# and Java, JavaScript is an interpreted language. It means that it needs an "interpreter". In case of JavaScript, the interpreter is the browser (or NodeJS ;-))

Introducció

JavaScript és un llenguatge de programació orientat a objectes dinàmic amb types and operators, standard built-in objects, and methods. Its syntax is based on the Java and C languages — so many structures from those languages apply to JavaScript as well.

Una de les principals diferències de JavaScript és que no té classes tot i ser orientat a objectes! La funcionalitat de les classes s'aconsegueix amb object prototypes

L'altre principal diferència és que les funcions són objectes donant a les funcions la capacitat de tenir codi executable que es pot moure d'un lloc a un altre com qualsevol objecte.

Història

It's useful to start with an overview of the language's history. JavaScript was created in 1995 by Brendan Eich, an engineer at Netscape, and first released with Netscape 2 early in 1996. (It was originally going to be called LiveScript, but was renamed in an ill-fated marketing decision in an attempt to capitalize on the popularity of Sun Microsystem's Java language — despite the two having very little in common. This has been a source of confusion ever since.)

Several months later, Microsoft released JScript, a mostly-compatible JavaScript work-alike, with Internet Explorer 3. Several months after that, Netscape submitted JavaScript to Ecma International, a European standards organization, which resulted in the first edition of the ECMAScript standard that year. The standard received a significant update as ECMAScript edition 3 in 1999, and has stayed pretty much stable ever since. The fourth edition was abandoned, due to political differences concerning language complexity. Many parts of the fourth edition formed the basis for ECMAScript edition 5, published in December of 2009, and for the 6th major edition of the standard, published in June of 2015.

Resources:

Versions

The JavaScript standard is ECMAScript. As of 2012, all modern browsers fully support ECMAScript 5.1. Older browsers support at least ECMAScript 3. As of June 2015 the spec for ES6/ES2015 has been approved. See the ECMAScript 2015 Language Specification at Ecma International. A good reference to versions, references and news about JavaScript can be found at the Mozilla Developer Network.

Conceptes

The DOM

The Document Object Model (DOM) is an API for HTML and XML documents. It provides a structural representation of the document, enabling you to modify its content and visual presentation by using a scripting language such as JavaScript.

Resources:

Host environments

Unlike most programming languages, the JavaScript language has no concept of input or output. It is designed to run as a scripting language in a host environment, and it is up to the host environment to provide mechanisms for communicating with the outside world. The most common host environment is the browser, but JavaScript interpreters can also be found in a huge list of other places, including Adobe Acrobat, Adobe Photoshop, SVG images, Yahoo's Widget engine, server-side environments such as Node.js, NoSQL databases like the open source Apache CouchDB, embedded computers, complete desktop environments like GNOME (one of the most popular GUIs for GNU/Linux operating systems), and others.

Code Style

Google té una guia:

https://google.github.io/styleguide/javascriptguide.xml

O podeu mirar idiomatic.js:

https://github.com/rwaldron/idiomatic.js

Inserir javascript a un fitxer html

<script type="text/javascript">
document.getElementById("demo").innerHTML=Date();
</script>

Javascript Scope

Llegiu també: http://www.w3schools.com/js/js_scope.asp

Les declaracions de les variables es processen abans que s'executi cap altre codi. El scope d'una variable ve donat pel seu context i bàsicament la norma és que si una variable és declara dins d'una funció aleshores esdevé una variable local a la funció i si es declarà fora o no es declarà esdevé una variable global (oco però si esteu treballant amb node que és diferent: vegeu global).

Les variables es poden declarar amb var:

var variable = "valor inicial"

o assignar un valor directament sense declarar (undeclared):

variable = "valor inicial"

Les diferències són:

  • Les variables declarades són locals al context d'execució i les no declarades són globals:
function x() {
  y = 1;   // Throws a ReferenceError in strict mode
  var z = 2;
}

x();

console.log(y); // logs "1" 
console.log(z); // Throws a ReferenceError: z is not defined outside x
  • Les variables declarades es creen abans que cap altre codi sigui executat en canvi les no declarades no
console.log(a);                // Throws a ReferenceError.
console.log('still going...'); // Never executes.
var a;
console.log(a);                // logs "undefined" or "" depending on browser.
console.log('still going...'); // logs "still going...".
  • Les variables declarades són una propietat no configurable del seu entorn d'execució i les no declarades són configurables (poden ser esborrades)
var a = 1;
b = 2;
delete this.a; // Throws a TypeError in strict mode. Fails silently otherwise.
delete this.b;
console.log(a, b); // Throws a ReferenceError. 
// The 'b' property was deleted and no longer exists.

Com que aquestes diferències només poden portar a problemes es recomana declarar sempre les variables. A ECMAScript 5 existeix el strict mode que obliga a declarar les variables sinó la interpretació del codi llança un error.

Resources


Var hoisting

var hoisting

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

bla = 2
var bla;
// ...
// is implicitly understood as:
var bla;
bla = 2;

For that reason, it is recommended to always declare variables at the top of their scope (the top of global code and the top of function code) so it's clear which variables are function scoped (local) and which are resolved on the scope chain.

Javascript Orientat a Objectes

NOTA: ECMAScript 6 ja és la nova versió de Javascript (--acacha (discussió) 16:49, 5 maig 2016 (CEST)) i per tant cal tenir-la en compte.
Vegeu també Prototypal OO
Codi font: https://github.com/acacha/TinkeringJavascript

A Javascript no existeixen les classes (no hi ha una declaració de classe tipus class NomClasse) sinó que simplement les classes són funcions:

function Persona() {
}

var persona1 = new Persona();
var persona2 = new Persona();

IMPORTANT: A ECMAScript 6 s'introdueixen les classes com a Syntax sugar: [1]

Javascript utilitzar una programació orientada a objectes on les classes no són presents i la reutilització de comportament (herència) es realitza amb un procés de decoració dels objectes existents que serveixen com exemples o el que es coneix com prototips. Aquest model és conegut com a programació sense classes o orientat a prototips.

Constructors

this vs bind: https://www.youtube.com/watch?v=GhbhD1HR5vk&index=1&list=PL0zVEGEvSaeHBZFy6Q8731rcwk0Gtuxub | https://www.youtube.com/watch?v=PIkA60I0dKU&index=2&list=PL0zVEGEvSaeHBZFy6Q8731rcwk0Gtuxub
new applied to function: https://www.youtube.com/watch?v=DqGwxR_0d1M&index=5&list=PL0zVEGEvSaeHBZFy6Q8731rcwk0Gtuxub

Vegem exemples més elaborats. Per exemple com definir un constructor (aka function constructors):

function Persona() {
  alert('Una instancia de Persona');
}

var persona1 = new Persona();
var persona2 = new Persona();

O amb node podem utilitzar el codi:

function Persona() {
    console.log('Una instancia de Persona');
}

var persona1 = new Persona();
var persona2 = new Persona();

NOTA: Alert és un mètode de Window l'objecte principal de Javascript en navegadors [2]. En canvi console està disponible tant en web com node i és una forma millor de fer "xivatos". Amb Chrome-dev-tools o els inspectors de codi dels navegadors o eines com Firebug podeu accedir a la consola javascript

IMPORTANT: Javascript ofereix moltes possibilitats i és molt flexible. Altres opcions són Prototypal OO/Object.create

Altres alternatives per crear objectes

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

Podem utilitzar també les opcions:

 new Object()

o

 Object.create()

O la literal notation (aka initializer notation) similar a JSON

Vegeu també Object

Propietats

Vegem un exemple de com definir propietats a un objecte:

function Persona(primerNombre) {
  this.primerNombre = primerNombre;
  console.log('Una instancia de Persona');
}

var persona1 = new Persona("Alicia");
var persona2 = new Persona("Sebastian");

// Muestra el primer nombre de persona1
console.log('persona1 es ' + persona1.primerNombre); // muestra "persona1 es Alicia"
console.log('persona2 es ' + persona2.primerNombre); // muestra "persona2 es Sebastian"

Proveu el codi amb:

$ node Persona2.js

Suposant heu guardat el codi a un fitxer Persona2.js o executant a un navegador amb:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Prova propietats</title>
</head>
<body>
Prova propietats. Consulteu la consola Javascript
<script src="Persona2.js"></script>

</body>
</html>

També es pot accedir a les propietats amb la notació d'arrays:

objectName["propertyName"]

Recorrent totes les propietats d'un objecte

Amb ECMAScript 5 podem:

Utilitzar Object.keys(o)

Mètodes

Ara veiem un objecte amb mètode:

function Persona(primerNombre) {
  this.primerNombre = primerNombre;
}

Persona.prototype.diHola = function() {
  console.log ('Hola, Soy ' + this.primerNombre);
};

var persona1 = new Persona("Alicia");
var persona2 = new Persona("Sebastian");

// Llamadas al método diHola de la clase Persona.
persona1.diHola(); // muestra "Hola, Soy Alicia"
persona2.diHola(); // muestra "Hola, Soy Sebastian"

Finalment observeu les característiques específiques de Javascript com el fet de poder assignar una funció, un objecte o el que sigui a una variable i com les variables globals s'assignen al objecte global (en els navegadors l'objecte Window):

function Persona(primerNombre) {
    this.primerNombre = primerNombre;
}

Persona.prototype.diHola = function() {
    console.log ("Hola, Soy " + this.primerNombre);
};

var persona1 = new Persona("Alicia");
var persona2 = new Persona("Sebastian");
var funcionSaludar = persona1.diHola;

persona1.diHola();                            // muestra "Hola, Soy Alicia"
persona2.diHola();                            // muestra "Hola, Soy Sebastian"
funcionSaludar();                             // muestra "Hola, Soy undefined (ó da un error con el
                                              // TypeError en modo estricto

console.log(funcionSaludar === persona1.diHola);            // muestra true (verdadero)
console.log(funcionSaludar === Persona.prototype.diHola);   // muestra true (verdadero)
funcionSaludar.call(persona1);    

Herència

La herència és una forma de crear una classe basada en un altre que serveix com a referència o pare sent la classe filla una versió especialitzada de la classe pare. Javascript només permet herència simple.

JavaScript no detecta la clase hija prototype.constructor, vea las propiedades del Core JavaScript 1.5 Reference:Global Objects:Object:prototype, así que debemos decírselo de forma manual.

Vegem un exemple:

En el siguiente ejemplo definimos la clase Estudiante como una clase secundaria de Persona . Luego redefinimos el método diHola() y agregamos el método diAdios().

// Definimos el constructor Persona
function Persona(primerNombre) {
  this.primerNombre = primerNombre;
}

// Agregamos un par de métodos a Persona.prototype
Persona.prototype.caminar = function() {
  alert("Estoy caminando!");
};
Persona.prototype.diHola = function(){
  alert("Hola, Soy" + this.primerNombre);
};

// Definimos el constructor Estudiante
function Estudiante(primerNombre, asunto) {
  // Llamamos al constructor padre, nos aseguramos (utilizando Function#call) que "this" se
  // ha establecido correctamente durante la llamada
  Persona.call(this, primerNombre);

  //Inicializamos las propiedades específicas de Estudiante
  this.asunto = asunto;
};

// Creamos el objeto Estudiante.prototype que hereda desde Persona.prototype
// Nota: Un error común es utilizar "new Persona()" para crear Estudiante.prototype 
// Esto es incorrecto por varias razones, y no menos importante, nosotros no le estamos pasando nada
// a Persona desde el argumento "primerNombre". El lugar correcto para llamar a Persona
// es arriba, donde nosotros llamamos a Estudiante.
Estudiante.prototype = Object.create(Persona.prototype);    // Vea las siguientes notas

// Establecer la propiedad "constructor" para referencias  a Estudiante
Estudiante.prototype.constructor = Estudiante;

// Remplazar el método "diHola"
Estudiante.prototype.diHola = function(){
  alert("Hola, Soy " + this.primerNombre + ". Yo estoy estudiando " + this.asunto + ".");
};

// Agregamos el método "diAdios"
Estudiante.prototype.diAdios = function() {
  alert("¡ Adios !");
};

// Ejemplos de uso
var estudiante1 = new Estudiante("Carolina", "Física Aplicada");
estudiante1.diHola();    // muestra "Hola, Soy Carolina. Yo estoy estudianto Física Aplicada."
estudiante1.caminar();   // muestra "Yo estoy caminando !"
estudiante1.diAdios();   // muestra "¡ Adios !"

// Comprobamos que las instancias funcionan correctamente
alert(estudiante1 instanceof Persona);      // devuelve true
alert(estudiante1 instanceof Estudiante);   // devuelve true
//Con respecto a la línea: 
Estudiante.prototype = Object.create(Persona.prototype); 
//Sobre los motores antiguos de JavaScript sin Object.create, se puede utilizar un polyfill (aka "shim", vea el enlace del artículo), o se puede utilizar una función que obtiene el mismo resultado, /como por ejemplo:
//
//function crearObjeto(proto) {
//  function ctor() { }
//  ctor.prototype = proto;
//  return new ctor();
//}

// uso:
Estudiante.prototype = crearObjeto(Persona.prototype);

Funció extends

Underscore.js té una funció http://underscorejs.org/#extend
http://davidshariff.com/blog/javascript-inheritance-patterns/

Es pot implementar una funció extends amb una funció:

/**
 * Point a child's prototype to a parent's prototype
 **/
var extendObj = function(childObj, parentObj) {
    childObj.prototype = parentObj.prototype;
};

Mixins

Els mixins fan referència a una forma de reutilitzar funcions entre objectes. Vegeu el següent esquema:

https://javascriptweblog.files.wordpress.com/2011/05/mixin3.jpg?w=1108

Com podeu observar hi haurà similituds (funcions similars) entre els objectes Button, Rectangle, Circle i Oval i en aquest cas estarem tots d'acord que serà molt difícil utilitzar el clàssic sistema d'herència en aquest cas (vegeu Delegation vs Inheritance). Podem definir una funció i reutilitzar-la utilitzant-la com a prototype en objectes.

var asCircle = function() {
  this.area = function() {
    return Math.PI * this.radius * this.radius;
  };
  this.grow = function() {
    this.radius++;
  };
  this.shrink = function() {
    this.radius--;
  };
  return this;
};
 
var Circle = function(radius) {
    this.radius = radius;
};
asCircle.call(Circle.prototype);
var circle1 = new Circle(5);
circle1.area(); //78.54

Vegeu també l'article Mixins per veure com s'utilitzen en altres entorns com CSS o PHP (Traits)

I podem utilitzar el mateix mixins en múltiples objectes:


var RoundButton = function(radius, label, action) {
    this.radius = radius;
    this.label = label;
    this.action = action;
};
 
asButton.call(RoundButton.prototype);
asCircle.call(RoundButton.prototype);
 
var button1 = new RoundButton(4, 'yes!', function() {return 'you said yes!'});
button1.fire(); //'you said yes!'

Vegeu també:

Recursos:

Underscore.js
var myMixins = {

  moveUp: function(){
    console.log( "move up" );
  },

  moveDown: function(){
    console.log( "move down" );
  },

  stop: function(){
    console.log( "stop! in the name of love!" );
  }

};
We can then easily extend the prototype of existing constructor functions to include this behavior using a helper such as the Underscore.js _.extend() method:

// A skeleton carAnimator constructor
function carAnimator(){
  this.moveLeft = function(){
    console.log( "move left" );
  };
}

// A skeleton personAnimator constructor
function personAnimator(){
  this.moveRandomly = function(){ /*..*/ };
}

// Extend both constructors with our Mixin
_.extend( carAnimator.prototype, myMixins );
_.extend( personAnimator.prototype, myMixins );

// Create a new instance of carAnimator
var myAnimator = new carAnimator();
myAnimator.moveLeft();
myAnimator.moveDown();
myAnimator.stop();

// Outputs:
// move left
// move down
// stop! in the name of love!

Objectes globals

Llista completa: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales

Existeixen múltiples objectes predefinits de sèrie (aka built-in objects) com Math

alert (Math.random ());

Hi ha un objecte global als navegadors que és Window ([3],[4]). De fet a l'exemple anterior l'estem utilitzant amb el mètode alert que realment és:

Window.alert (Math.random ());

Cal tenir en compte que Node.js té els seus propis objectes globals:

https://nodejs.org/api/globals.html

I que l'objecte global per defecte no és Window (té lògica ja que es pot executar fora d'un browser, per exemple sovint per la CLI) sinó l'objecte global ([5])

Recursos

Objecte global Object

https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object

Facilita el treball amb objectes. ES pot utilitzar per exemple com una mena de stdClass de PHP:

var myCar = new Object();
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;

De fet es pot fer tot en una sola línia:

 var myCar = new Object(),
    make = "Ford",
    model = "Mustang",
    year =1969,
    rand = Math.random(),
    obj = new Object();

Object Literal syntax

Un exemple de Object Literal syntax:

var myObjLiteral = {
  defaults: { name: 'Todd' },
  someMethod: function () {
    console.log(this.defaults);
  }
};

// console.log: Object { name: 'Todd' }
myObjLiteral.someMethod();

NOTA: Amb ECMAScript 6 i l'aparició de class observeu com class pot ser una alternativa a Object Literal syntax i com de fet per diferenciar clarament les dos alternatives a class no s'utilitza cap separador entre mètodes i/o atributs. Amb Object Literal syntax el separador és "," no permès a class (si és permet ; però no és obligatori)

IMPORTANT: Vegeu Javascript Module Pattern com un altre forma de crear "classes" però que permet definir encapsulació amb mètodes privats i mètodes públics fet que permet definir una API al mòdul/objecte

Cal tenir en compte les millores introduïdes ES6 que permeten evitar molt codi repetitiu/boilerplate (https://laracasts.com/series/es6-cliffsnotes/episodes/5):


function getCar(make, model, value) {
	return {
		// with property value shorthand
		// syntax, you can omit the property
		// value if key matches variable
		// name
		make,  // same as make: make
		model, // same as model: model
		value, // same as value: value

		// computed values now work with
		// object literals
		['make' + make]: true,

		// Method definition shorthand syntax
		// omits `function` keyword & colon
		depreciate() {
			this.value -= 2500;
		}
	};
}

Prototypal OO

http://davidshariff.com/blog/javascript-inheritance-patterns/

Prototypal OO

La orientació a objectes per prototips és un alternativa a la orientació a objectes clàssica o orientació a objectes per classes. La principal diferència entre els dos sistemes està en la relació entre objectes especialment pel que fa a l'herència. En la programació orientada a objectes per classes s'utilitza normalment una paraula reservada com extends per definir una relació jeràrquica tipus pare/fill entre dos objectes. Amb Javascript s'utilitza el concepte de prototip on cada objecte té un prototip. Els prototips són també objectes de forma que d'aquesta forma tenim una forma de relacionar dos objectes. De fet aquest sistema forma una cadena anomenada cadena de prototips on un objecte té un prototip que al seu torn té un altre prototip i així fins arribar a un objecte que no té cap prototip definit (valor null).

NOTA: ES6 introdueix la paraula reservada class però atenció només és syntax sugar és a dir que la programació orientada a objectes amb Javascript continua sent basada en prototips

Herència de propietats

Nota: sovint en Javascript es prefereix utilitzar el tema delegació en comptes de herència per que el sistema de protototips el que fa és delegar. Vegeu Delegation vs Inheritance in JavaScript

Les propietats funcionen d'una forma molt senzilla en objectes Javascript simplement es busquen a tota la cadena de prototips i sinó es troben a la cadena aleshores es retorna el valor undefined.

Vegem un exemple:

// Suposem tenim dos objectes:
// {a: 1, b: 2}
// o.[[Prototype]] has properties b and c:
// {b: 3, c: 4}
// Finally, o.[[Prototype]].[[Prototype]] is null.
// This is the end of the prototype chain as null,
// by definition, null has no [[Prototype]].
// Thus, the full prototype chain looks like:
// {a:1, b:2} ---> {b:3, c:4} ---> null

console.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.

console.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited. 
// This is called "property shadowing"

console.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.

console.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined

Property shadowing és el nom que s'utilitza a Javascript per al que en altres llenguatges coneixem com sobreescriptura de mètodes.

Herència de mètodes. Afegir mètodes al prototip

Exemple Hola mon!:


function Greeter(name) {
   this.name = name || 'John Doe';
}

Greeter.prototype.hello = function hello() {
   return 'Hello my name is ' + this.name;
}

var george = new Greeter('George');
george.hello();

Atenció!: La herència és una mica complexa de detectar en aquest cas george és un Objecte que hereta de Greeter el mètode hello. Vegem un altre alternativa amb l'objecte especial de Javascript Object i el seu mètode Object.create (no s'assembla tant a l'orientació a objectes "clàssica" i és més per prototips):


var proto = {
  hello: function hello() {
    return 'Hello my name is ' + this.name;
  }
};

var george = Object.create(proto);
george.name = 'George';

On podem observar com creem un objecte a partir d'un prototip.

Un altre alternativa (Mixin Style, vegeu mixins):


var proto = {
  hello: function hello() {
    return 'Hello my name is ' + this.name;
  }
};

var george = _.extend({}, proto, {name: 'George'});

Recursos:

Delegation vs Inheritance in JavaScript

https://javascriptweblog.wordpress.com/2010/12/22/delegation-vs-inheritance-in-javascript/
http://www.javaworld.com/article/2073649/core-java/why-extends-is-evil.html

Una frase:

Utilitzar l'herència com una forma de reutilització de codi és com demanar un Happy Meal simplement per què volem el joguet! 

Una alternativa és utilitzar Delegation (el sistema de prototips de Javascript està més orientat en aquesta direcció)

La delegació és una tècnica que promou la reutilització de codi permeten la invocació en runtime de funcions en el context d'una instància especifica. Vegeu:


Class i ECS6

A ECS6 tenim syntax sugar per a definir objectes utilitzant la paraula reservada class i per tant de forma molt similar a llenguatges de programació clàsics o no orientats a prototips.

IMPORTANT: Class Només és syntax sugar, és a dir, continua sent un sistema orientat a prototips i no pas el sistema tradicional

Abans (ECMAScript 5):

var Shape = function (id, x, y) {
    this.id = id;
    this.move(x, y);
};
Shape.prototype.move = function (x, y) {
    this.x = x;
    this.y = y;
};

ECMAScript 6:

class Shape {
    constructor (id, x, y) {
        this.id = id
        this.move(x, y)
    }
    move (x, y) {
        this.x = x
        this.y = y
    }
}
</pre

I es poden definit setters/getters, extends, super ,static members ([http://es6-features.org/#ClassInheritance]):

<pre class="brush:javascript">

class Rectangle extends Shape {
    constructor (id, x, y, width, height) {
        super(id, x, y)
        this.width  = width
        this.height = height
    }
}
class Circle extends Shape {
    constructor (id, x, y, radius) {
        super(id, x, y)
        this.radius = radius
    }
}

Amb ECMAScript 5:


var Rectangle = function (id, x, y, width, height) {
    Shape.call(this, id, x, y);
    this.width  = width;
    this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var Circle = function (id, x, y, radius) {
    Shape.call(this, id, x, y);
    this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;


Recursos:

  • Javascript#Javascript_Orientat_a_Objectes

Javascript patterns

En aquesta secció veurem alguns dels patrons més utilitzats a Javascript (Javascript patterns)

Resources;

Javascript module pattern

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
http://jstherightway.org/ 
Revealing Module Pattern

El Javascript module pattern consisteix en crear una funció anònima (aka anonymous function o Anonymous Closure ), posar codi dins la funció i executar-la immediatament. L'snippet bàsic seria:

(function () {
	// ... all vars and functions are in this scope only
	// still maintains access to all globals
}());

Quin avantatge té respecte a executar codi directament? Doncs que tot el codi que s'executa al closure té com scope el closure i per tant té una local scope. S'utilitza per crear mòduls independents de codi amb Javascript.

NOTA: Vegeu també Node.js i com per defecte aconsegueix la modularitat amb un fitxer per mòdul

En certa manera aquest patró s'utilitza per a simular el patró típic en programació orientada a objectes:

class {

}

Recordeu que Javascript també és un patró orientat a objectes però que no utilitza classes (vegeu Javascript orientat a Objectes). Bàsicament una classe permet encapsular, és a dir posar una sèrie de propietats/variables i funcions/mètodes en un mateix mòdul o paquet. Amb aquest patró és limita l'ús de variables globals evitant així les possibilitat de col·lisió de codi.

El module pattern és de lluny el patró més utilitzat en Javascript i s'utilitza per exemple en projectes com jQuery, Dojo, ExtJS o YUI.

Vegem com es pot crear un mòdul:

var ModuleName = (function () {
  // code
})();

On ModuleName és un Javascript namespace és a dir funciona com una mena de prefix que haurem de posar per a accedir a tota la funcionalitat del mòdul: variables/propietats i mètodes/funcions.

Entrem una mica més en detall i vegem per exemple com podem definit un mètode privat:

var Module = (function () {

        var privateMethod = function () {
            console.log('Soc privat!');
        };

    })();
    //Thows error: Uncaught TypeError: Cannot read property 'privateMethod' of undefined
    //Module.privateMethod();

I un mètode public:


// Public method
    var Module2 = (function () {

        return {
            publicMethod: function () {
                console.log('Soc privat!');
            }
        };

    })();
    // As we’re returning an Object Literal, we can call them exactly like Object Literals:
    Module2.publicMethod();

O una barreja de tots dos casos amb mètodes privats i públics:

var Module = (function () {

  var privateMethod = function () {};
  
  return {
    publicMethodOne: function () {
      // I can call `privateMethod()` you know...
    },
    publicMethodtwo: function () {

    },
    publicMethodThree: function () {

    }
  };

})();

Un altre sintaxi possible per deixar clar quina és la API (el conjunt de mètodes públics del mòdul) pot ser:

var Module = (function () {

  var privateMethod = function () {
    // private
  };

  var someMethod = function () {
    // public
  };

  var anotherMethod = function () {
    // public
  };
  
  return {
    someMethod: someMethod,
    anotherMethod: anotherMethod
  };

})();

Resources:

Herència: augmentant o decorant mòduls

aka Augmentation

Vegem com es pot augmentar/estendre les funcionalitats d'un mòdul:

var Module = (function () {

  var privateMethod = function () {
    // private
  };

  var someMethod = function () {
    // public
  };

  var anotherMethod = function () {
    // public
  };
  
  return {
    someMethod: someMethod,
    anotherMethod: anotherMethod
  };

})();

Tenim dos la següent API un objecte amb dos mètodes:

Object {someMethod: function, anotherMethod: function}

I volem afegir un mètode extension :

Object {someMethod: function, anotherMethod: function, extension: function}

Fàcil:

var ModuleTwo = (function (Module) {
    
    // access to `Module`
    
})(Module);
We could then create another method inside this module, have all the benefits of private scoping/functionality and then return our extension method. My pseudo code could look like this:

var ModuleTwo = (function (Module) {
    
    Module.extension = function () {
        // another method!
    };
    
    return Module;
    
})(Module || {});

Hi ha múltiples patrons:

Augmentation simple:

var MODULE = (function (my) {
	my.anotherMethod = function () {
		// added method...
	};

	return my;
}(MODULE));

Loose Augmentation

No depenem del "pare" (que no doni error sinó existeix):


var MODULE = (function (my) {
	// add capabilities...

	return my;
}(MODULE || {}));

Tight Augmentation

Loose augmentation és una bona solució però té algunes limitacions al crear mòduls. La més important que no es poden sobrescriure propietats del mòdul de forma senzilla.

Vegem un exemple:

var MODULE = (function (my) {
	var old_moduleMethod = my.moduleMethod;

	my.moduleMethod = function () {
		// method override, has access to old through old_moduleMethod...
	};

	return my;
}(MODULE));

Exemples

Avantatges e inconvenients

Advantages

  • Cleaner approach for developers
  • Supports private data
  • Less clutter in the global namespace
  • Localization of functions and variables through closures

Disadvantages:

  • Private methods are unaccessible.
  • Some people say that this leads to the inability of unit testing but more often than not, if you're questioning the integrity of a function, it should probably be engineered in such a fashion that exposes the utility of that function publicly, thus making it testable. Given the adaptation of the module pattern by jQuery and their everyday use of QUnit to automate testing, this bullet point isn't really relevant but still listed for documentation purposes.
  • Private methods and functions lose extendability since they are unaccessible (see my comment in the previous bullet point).

Perquè s'utilitza window o document o altres com a paràmetre?

La resposta curta és primer que és opcional i no cal i que s'utilitza per tal de ser més fàcil saber quines variables globals estem utilitzant, quan fem:

(function (foo, bar) {
    return foo.getElementById(bar);
})(document, "myElement")

Estem creant un funció anònima a la que li passem document i myElement com a paràmetres. Sinó passesim estes variables explícitament al ser variables globals estarien implícitament disponibles dins del mòdul però així queda més clar. El resultat és dins la funció que

return foo.getElementById(bar);

equival a (a l'exemple!):

document.getElementById("myElement").

Sovint veurem coses com:

function($)

On passem implícitament Jquery o window:

var MyModule = ( function( window ) {
  
  function myMethod() {
    alert( 'my method' );
  }
  
  function myOtherMethod() {
    alert( 'my other method' );
  }
  
  // explicitly return public methods when this object is instantiated
  return {
    someMethod : myMethod,
    someOtherMethod : myOtherMethod
  };
  
} )( window );


Vegeu:

Perquè s'utilitza undefined com a paràmetre?

Recursos:

Perquè s'utilitza undefined com a paràmetre?

Cal entendre que no és necessari, però que té avantatges vegeu:

http://stackoverflow.com/questions/9602901/what-is-the-purpose-of-passing-in-undefined

Exemple:

var MyModule = ( function( window, undefined ) {
  
  function myMethod() {
    alert( 'my method' );
  }
  
  function myOtherMethod() {
    alert( 'my other method' );
  }
  
  // explicitly return public methods when this object is instantiated
  return {
    someMethod : myMethod,
    someOtherMethod : myOtherMethod
  };
  
} )( window );

//  example usage
MyModule.myMethod(); // undefined
MyModule.myOtherMethod(); // undefined
MyModule.someMethod(); // alerts "my method"
MyModule.someOtherMethod(); // alerts "my other method"

Recursos:

Javascript Module Systems

Vegeu Javascript Module Systems

ECMAScript 6

Vegeu ECMAScript 6

Funcions de validació

DNI, NIE i comptes bancaries Espanya

email

function checkEmail(control) {
	var filter = /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/;
	if (!filter.test(control.value)) {
		alert('Email incorrecte!');
		control.focus
		return false;
	}
}

Javascript i Apache

No funciona javascript a Apache. /etc/apache2/conf.d/javascript-common.conf

Si teniu una aplicació web instal·lada a l'arrel del vostre servidor web i aquesta aplicació té una carpeta anomenada javascript amb el codi javascript propi de l'aplicació, aleshores és possible que xoqueu amb la configuració del fitxer:

$ cat /etc/apache2/conf.d/javascript-common.conf

La sol·lució ha estat utilitzar enllaços simbòlics que apuntin a la carpeta Javascript, per exemple per a l'aplicació Intraweb:

$ cd /usr/share/javascript
$ sudo ln -s /var/www/intraweb/maqueta_2.2/intranet/javascript/* .


Podeu trobar els usos de carpetes Javascript a Apache amb grep:

$ cd /etc/apache2
$ grep -n "javascript" -r .
./sites-enabled/000-default:11:	<Directory /var/www/intraweb/maqueta_2.2/intranet/javascript>
./conf.d/javascript-common.conf:1:Alias /javascript /usr/share/javascript/
./conf.d/javascript-common.conf:3:<Directory "/usr/share/javascript/">
./sites-available/default:11:	<Directory /var/www/intraweb/maqueta_2.2/intranet/javascript>
./mods-enabled/deflate.conf:7:          AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
./mods-available/deflate.conf:7:          AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript

AJAX/AJAJ

Vegeu l'article AJAX

Frameworks

Mobile

Paquets javascript-common i wwwconfig-common

Instal·lació:

$ sudo apt-get install javascript-common

Com podeu veure, el paquet wwwconfig-common és una dependència i també s'instal·la.

Per aplicar els canvis:

$ sudo /etc/init.d/apache2 reload

Fitxers instal·lats:

$ dpkg -L javascript-common
/.
/usr
/usr/share
/usr/share/lintian
/usr/share/lintian/overrides
/usr/share/lintian/overrides/javascript-common
/usr/share/doc
/usr/share/doc/javascript-common
/usr/share/doc/javascript-common/copyright
/usr/share/doc/javascript-common/README.Debian
/usr/share/doc/javascript-common/changelog.gz
/usr/share/javascript
/etc
/etc/javascript-common
/etc/javascript-common/lighttpd.conf
/etc/javascript-common/javascript-common.conf

A més es crea l'enllaç simbòlic:

$ ls -la /etc/apache2/conf.d/javascript-common.conf
total 24
drwxr-xr-x 2 root root 4096 mar 31 19:59 .
drwxr-xr-x 7 root root 4096 mar 31 10:21 ..
-rw-r--r-- 1 root root  269 feb  7  2012 charset
lrwxrwxrwx 1 root root   26 jul 23  2012 gosa.conf -> /etc/gosa/gosa-apache.conf
lrwxrwxrwx 1 root root   45 mar 31 19:59 javascript-common.conf -> /etc/javascript-common/javascript-common.conf

El README ho diu clarament:

$ cat /usr/share/doc/javascript-common/README.Debian
javascript-common for Debian
----------------------------

Packages installed in /usr/share/javascript/ are exposed to Apache in
http://localhost/javascript and can be used by through the following lines in
your html headers:

	<script language="javascript" type="text/javascript"  src="/javascript/package/lib.js"></script>

 -- Marcelo Jorge Vieira (metal) <metal@badhorse.alucinados.com>  Tue, 12 Feb 2008 16:16:52 -0200

Paquets com libjs-jquery sugereixen o tenen com a dependencia:

$ apt-cache depends libjs-jquery
libjs-jquery
  Sugiere: javascript-common
  ...

I així poder fer accesible jquery des de la URL:

http://localhost/javascript/jquery/jquery.js

o

<script language="javascript" type="text/javascript"  src="/javascript/jquery/jquery.js"></script>

Gestió de paquets

Vegeu:

Moduls, namespaces i scopes

Vegeu Javascript_modules

Troubleshooting. Resol·lució de problemes

Flash of unstyled content

Flash of unstyled content aka FOUC vegeu:

Alguns sistemes com vue.js utilitzant una directiva que es diu v-cloack que serveix per evitar aquest efecte? Vegeu:

http://vuejs.org/api/#v-cloak

Per exemple Laravel Spark posa tot el continugt vue.js dins d'un div amb:

<div id="spark-app" v-cloak>
</div>

I simplmeent hi ha un full d'estil que no mostra el div si està amb v-cloack. Més info a:

https://gist.github.com/adamwathan/3584d1904e4f4c36096f

Vegeu també

Enllaços externs