JavaScript Object Oriented

Preview:

DESCRIPTION

Continuando a parlare di JavaScript ...

Citation preview

OO JAVASCRIPT

Sviluppo applicazioni web e linguaggio HTML

LEZIONE 03

JavaScript? E’ un linguaggio di

scripting Object-Oriented

interpretato da un

browser web

Tutto in JavaScript è un

oggetto, ovvero una

rappresentazione

di un concetto o di

una entità del

mondo reale

sotto forma di

dati + azioni

var comodino = new Object();

comodino.cassetti = 3;

comodino.colore = ‘Bianco’;

comodino.altezza = 400; // in millimetri

comodino.larghezza = 500;

comodino[‘profondità’] = 400;

var comodino = {

cassetti : 3,

colore : ‘Bianco’,

altezza : 400,

larghezza : 500,

‘profondità’ : 400

}

Notazione letterale

var a = [ ];

typeof a; // risultato: "object“

var misc = [ 3, ‘Bianco’, 400, 500, 400 ];

misc.length; // risultato: 5

JSON

var comodino = {

“cassetti” : 3, “colore” : “Bianco”,

“misure” : [

{ “altezza” : 400 },

{ “larghezza” : 500 }, { “profondità” : 400 }

]

}

… ma per oggetto si intende forse

istanza di una

classe?

Classi!? In JavaScript non esistono

function Comodino(colore, cassetti) {

this.colore = colore;

this.cassetti = cassetti;

return this; // facoltativo

};

var comodino = new Comodino(‘Bianco’, 3);

Il costruttore è una funzione

Apriamo una

parentesi sulle

funzioni

Le funzioni sono oggetti

un contesto di

esecuzione : this

un insieme di valori

passati come

parametri : arguments

un campo contenente

tutto il codice

function sum( ) {

var total = 0;

var count = arguments.length;

for(var i = 0; i < count; i++) {

total += arguments[i];

}

return total;

}

variadic function

sum( ); // risultato: 0

sum(1, 2, 3, 5, 6, 7); // risultato: 24

Una funzione assegnata

alla proprietà di un

oggetto è un metodo

var comodino = {

cassetti : 3,

colore : ‘Bianco’,

altezza : 400,

larghezza : 500,

‘profondità’ : 400,

dimensioni : function( ){

return this.larghezza + ‘x’ + this.altezza

+ ‘x’ + this[‘profondità’] + ‘ mm’;

}

}

anonymous function

comodino.dimensioni( );

// risultato: 500x400x400 mm

Lo scope di una variabile è

limitato alla funzione nella

quale la variabile è stata dichiarata

var zoccolo = ’80 millimetri’;

var altezza = function(comodino) {

var altezza_zoccolo = parseInt(zoccolo);

return comodino.altezza

+ altezza_zoccolo;

};

variabile globale Accessibile da tutta

l’applicazione

var zoccolo = ’80 millimetri’;

var altezza = function(comodino) {

var altezza_zoccolo = parseInt(zoccolo);

return comodino.altezza

+ altezza_zoccolo;

};

variabile locale

Accessibile solo

all’interno della funzione

function foo( ) {

if ( true) {

var zoccolo = ‘80 millimetri’;

}

alert(zoccolo);

};

foo( );

Accessibile solo

all’interno della funzione

il contesto

di esecuzione di una funzione

dipende dal

tipo di chiamata

Se la funzione è chiamata

come metodo, il contesto è

l’oggetto al quale appartiene

var comodino = {

dimensioni : function( ){

return this.larghezza + ‘x’ + this.altezza

+ ‘x’ + this[‘profondità’] + ‘ mm’;

}

}

Se la funzione viene definita

globalmente a livello di

applicazione, il contesto è

l’oggetto globale (window)

var a = 1;

var b = 2;

var c = sum(this.a, this.b);

Per una funzione interna il

contesto è quello della

funzione esterna

var a = 5;

var foo = function( ) {

var a = 0;

var f = function(b){

a += b;

};

f(5);

return a;

};

foo(); // risultato: 5

var a = 5;

var foo = function( ) {

var a = 0;

var f = function(b){

this.a += b;

};

f(5);

return a;

};

foo(); // risultato: 0

a = 10

Cosa succede se chiamiamo una funzione

globale all’interno di una funzione interna?

var value = 0;

var obj = { value : 5 };

obj.add = function (a) {

var inner = function (){

this.value = sum(this.value, a);

};

inner();

return this.value;

};

obj.add(3);

Qual è il risultato

di obj.add(3)?

Cosa succede se chiamiamo una funzione

globale all’interno di una funzione interna?

var value = 0;

var obj = { value : 5 };

obj.add = function (a) {

var inner = function (){

this.value = sum(this.value, a);

};

inner();

return this.value;

};

obj.add(3);

Si riferisce all’oggetto

globale

Cosa succede se chiamiamo una funzione

globale all’interno di una funzione interna?

var value = 0;

var obj = { value : 5 };

obj.add = function (a) {

var inner = function (){

this.value = sum(this.value, a);

};

inner();

return this.value;

};

obj.add(3);

Si riferisce all’oggetto

globale

Creo una variabile that nel metodo esterno per

passare alla funzione globale il contesto locale

var value = 0;

var obj = { value : 5 };

obj.add = function (a) {

var that = this;

var inner = function (){

that.value = sum(that.value, a);

};

inner();

return this.value;

};

obj.add(3);

E se volessimo cambiare il

contesto di esecuzione? Con

il metodo apply si può!

var obj = { value : 5 };

obj.multiply = function(a){

return this.value * a;

};

obj.multiply(3);

var value = 2;

obj.multiply.apply(this, [3]);

parametri:

- nuovo contesto

- array di argomenti

Cosa succede se nel creare un oggetto mi

dimentico della parola chiave new?

var value = 0;

function Obj(value){

this.value = value;

};

var obj = Obj(5);

obj.value = 10;

Quale valore ho

modificato?

Cosa succede se nel creare un oggetto mi

dimentico della parola chiave new?

var value = 0;

function Obj(value){

this.value = value;

};

var obj = Obj(5);

obj.value = 10;

Quale valore ho

modificato?

Lo scope delle variabili di una

funzione viene determinato al

momento della sua definizione e

non quando questa viene eseguita

function foo( ) {

var a = 123;

bar( );

};

function bar( ) {

return a;

};

foo(); // risultato: undefined

In esecuzione il ritorno

di “a” da parte di bar()

avviene dopo la dichiarazione di “a”

ma il risultato è …

Lo scope di bar() al

momento della sua definizione è globale

function foo( ) {

var a = 123;

bar( );

};

function bar( ) {

return a;

};

foo(); // risultato: undefined

function foo( ) {

var a = 123;

var bar = function( ) {

return a;

};

return bar();

};

foo(); // risultato: 123

Lo scope di bar() al momento

della sua definizione è lo stesso di foo()

Le funzioni interne possono

accedere alle variabili e ai

parametri delle funzioni nelle

quali sono definite

var a = 14;

function foo( ) {

var b = 10;

function bar( ) {

var c = 3;

alert(a+b+c);

};

bar( );

};

foo(); // mostra 27

c

b

a

bar scope

foo scope

global scope

“A closure is formed when one of

those inner functions is made

accessible outside of the function in

which it was contained, so that it

may be executed after the outer

function has returned.”

http://jibbering.com/faq/notes/closures/

var obj = function ( ) {

var value = 1;

return {

add : function (a) { value += a; },

getValue : function ( ) { return value; }

}

}( );

obj.add(5);

obj.getValue(); // risultato: 6

function foo(arg) {

var bar = function(){

return arg;

};

arg++;

return bar;

};

var bar = foo(5);

bar(); // risultato: 6

function foo( ) {

var i, array = [ ];

for(i = 0; i < 3; i++) {

array[ i ] = function( ) {

return i;

};

}

return array;

};

var a = foo( );

a[0]( ); // risultato: 3

a[1]( ); // risultato: 3

a[2]( ); // risultato: 3

La funzione anonima

mantiene un riferimento allo

scope del parent

Le tre funzioni puntano

entrambe al valore di “i” terminata l’esecuzione di foo e quindi del loop

function foo( ) {

var i, array = [ ];

for(i = 0; i < 3; i++) {

array[ i ] = ( function( j ) {

return function( ) { return j; }

})( i );

}

return array;

};

var a = foo( );

a[0]( ); // risultato: 0

a[1]( ); // risultato: 1

a[2]( ); // risultato: 2

La funzione anonima

accetta “i“ come parametro

Adesso ogni funzione ha

“i” nel suo scope con il valore i-esimo del loop

// funzione con una callback come parametro

function foo(a, b, callback) {

var n = (a * b) + b;

callback(n);

}

foo (5, 2, function(n) {

alert("callback result: " + n);

});

anonymous function

Chiusa la

parentesi sulle

funzioni

In JavaScript non esistono classi …

function Comodino(colore, cassetti) {

this.colore = colore;

this.cassetti = cassetti;

return this; // facoltativo

};

var comodino = new Comodino(‘Bianco’, 3);

Il costruttore è una funzione

Ogni funzione ha una proprietà

prototype che è il prototipo degli

oggetti creati con quella funzione

typeof Comodino.prototype // risultato: object

Il prototipo mantiene in una proprietà

constructor il riferimento alla funzione

che lo ha generato

typeof Comodino.prototype.constructor

// risultato: Function

Comodino.prototype.constructor

// risultato: Comodino( )

Invece che inizializzare gli oggetti nel

costruttore lo posso fare con il prototype

function Comodino( ) { };

Comodino.prototype.cassetti = 3;

Comodino.prototype.colore = ‘Bianco’;

var comodino = new Comodino( );

comodino.cassetti // risultato: 3

Comodino.prototype.isProtoypeOf(comodino); // true

L’aggiunta di una proprietà nel prototipo

si riflette su tutti gli oggetti creati con

quel prototipo

function Comodino( ) { };

Comodino.prototype.cassetti = 3;

Comodino.prototype.colore = ‘Bianco’;

var comodino1 = new Comodino( );

var comodino2 = new Comodino( );

Comodino.prototype.altezza = 400;

comodino1.altezza; // risultato: 400

comodino2.altezza; // risultato: 400

augmentation

OK, ma non voglio mica tutti gli oggetti

uguali!

Comodino.prototype.altezza = 400;

comodino1.altezza; // risultato: 400

comodino2.altezza; // risultato: 400

comodino1.altezza = 300;

comodino1.altezza ; // risultato: 300

comodino2.altezza; // risultato: 400

comodino1.hasOwnProperty(‘altezza’); // true

comodino1.hasOwnProperty(‘altezza’); // false

shadowing

function Comodino(colore, cassetti) {

this.colore = colore;

this.cassetti = cassetti;

};

Comodino.prototype = {

constructor : Comodino,

altezza : 400

};

In JavaScript esiste

l’ereditarietà?

Interface inheritance

Implementation inheritance

NO

SI

Prototype Chaining

Classical Inheritance

Pseudoclassical Inheritance

Prototypal Inheritance

Prototype Chaining

Classical Inheritance

Pseudoclassical Inheritance

Prototypal Inheritance

function Mobile( ) {

this.materiali = [ ‘Legno’ ];

}

function Comodino( ) {

this.colore = ‘Bianco’;

}

// Comodino eredita da Mobile

Comodino.prototype = new Mobile();

var comodino = new Comodino( );

comodino.materiali[0]; // risultato: “Legno”

prototype chaining

...

// Comodino eredita da Mobile

Comodino.prototype = new Mobile();

var comodino1 = new Comodino( );

var comodino2 = new Comodino( );

comodino1.materiali.push(‘Vetro’);

comodino1.materiali; // ”Legno, Vetro”

comodino2.materiali; // ”Legno, Vetro”

Le proprietà impostate nel costruttore

diventano proprietà di prototipo e

quindi condivise

Prototype Chaining

Classical Inheritance

Pseudoclassical Inheritance

Prototypal Inheritance

function Mobile( ) {

this.materiali = [ ‘Legno’ ];

}

function Comodino( ) {

this.colore = ‘Bianco’;

Mobile.call(this);

}

var comodino1 = new Comodino( );

var comodino2 = new Comodino( );

comodino1.materiali.push(‘Vetro’);

comodino1.materiali; // ”Legno, Vetro”

comodino2.materiali; // ”Legno”

constructor stealing

I metodi devono essere

aggiunti sul costruttore base perché il prototipo non è visibile dai sottotipi

Prototype Chaining

Classical Inheritance

Pseudoclassical Inheritance

Prototypal Inheritance

La tecnica Pseudoclassical

Inheritance prende il meglio

dai due pattern precedenti,

utilizzando:

• prototype chaining per i

metodi

• constructor stealing per le

proprietà

function Mobile( prezzo ) {

this.materiali = [ ‘Legno’ ];

this.prezzo = prezzo;

}

Mobile.prototype.sconto = function( percentuale ) {

return this.prezzo * percentuale / 100;

};

function Comodino( prezzo, colore ) {

// eredita le proprietà

Mobile.call(this, prezzo);

this.colore = colore;

}

// eredita i metodi

Comodino.prototype = new Mobile ();

Prototype Chaining

Classical Inheritance

Pseudoclassical Inheritance

Prototypal Inheritance

function object(o) {

function F( ) { }

F.prototype = o;

return new F( );

}

var comodino1 = { materiali : [‘Legno’],

colore : ‘Bianco’ };

var comodino2 = object(comodino1);

comodino2.materiali.push(‘Vetro’);

comodino1.materiali; // “Legno”, “Vetro”

Prototypal Inheritance

(2006, Douglas Crockford)

Slide 3: http://www.flickr.com/photos/52701968@N00/14954425/

Slide 22: http://www.flickr.com/photos/msutherland1/2372319292/in/photostream/

Slide 53 : http://www.flickr.com/photos/pardeshi/1514977212

Credits Le immagini contenute in questa presentazione

hanno licenza Creative Commons

Thank You

MANUEL SCAPOLAN website: www.manuelscapolan.it twitter: manuelscapolan e-mail: info@manuelscapolan.it

Recommended