JavaScript orientado a objetos

Posted on 20/09/2011

12


Olá pessoal, tudo certo?

JavaScript vem ganhando relevância no desenvolvimento de aplicações. Por causa disso, é importante saber como usar essa linguagem de forma refinada. Se possível, com orientação a objetos.

No post de hoje, mostro os fundamentos de orientação a objetos usando JavaScript.

Antes de começar …

JavaScript não foi projetada para ser uma linguagem orienta a objetos. Além disso, há quem diga que pensar a linguagem dessa forma gere alguma confusão.

Alguns dos princípios de design a orientação a objetos podem ser aplicados, mas não todos.

Criando uma classe

Definir uma classe em JavaScript é tão simples quanto escrever uma função. Observe:

function Person() {
}

var p = new Person();

 

Só isso! Bacana, não!?

Sintaxe alternativa:

var Person = function () {
}

var p = new Person();

Definindo um construtor

Um construtor é um código opcional que pode ser executado quando uma instância de objeto é criada.

Dada essa breve explicação (momento pândego … ;-D ), em JavaScript um construtor pode ser definido pela simples adição de código na função que define a classe. Observe:

function Foo() {
    alert("Hello world from Foo constructor");
}

var f = new Foo();

Podemos passar parâmetros para o construtor facilmente. Observe:

var Foo = function (p) {
    alert("Foo constructor received " + p + " as p value");
}

var f = new Foo(2);

Definindo atributos públicos

Atributos públics são definidos junto com a classe, usando a palavra-chave [reservada] this. Repare:

var Foo = function () {
    this.name = "";
}

var f1 = new Foo();
f1.name = "Elemar Jr";

var f2 = new Foo();
f2.name = "Gabriel Severo";

alert("f1.name = " + f1.name + "\nf2.name = " + f2.name);

Combinando com construtores:

var Foo = function (name) {
    this.name = name;
}

var f1 = new Foo("Elemar Jr");
var f2 = new Foo("Gabriel Severo");

alert("f1.name = " + f1.name + "\nf2.name = " + f2.name);

Legal.

Definindo métodos

Agora, vamos ver como definir métodos. Como tudo em JavaScript, é bem simples. Observe:

var Foo = function (name) {
    this.name = name;
    this.sayHello = function () {
        alert("Hello from " + this.name);
    }
}

var f1 = new Foo("Elemar Jr");
var f2 = new Foo("Gabriel Severo");

f1.sayHello();
f2.sayHello();

Como pode ser observado, um método é definido de forma semelhante a um atributo.

Pausa para conhecer a palavra-chave prototype

Outra forma de definir propriedades e métodos para uma classe ocorre fora da definição. Isso, através da palavra-chave prototype. Observe:

var Foo = function (name) {
    this.name = name;
}

Foo.prototype.sayHello = function () {
    alert("Hello from " + this.name);
}; 

var f1 = new Foo("Elemar Jr");
var f2 = new Foo("Gabriel Severo");

Belo, não!?

Que tal um Singleton?

Se você usa orientação a objetos, então, deve conhecer Singleton. Em JavaScript, há mais de uma forma de implementar Singleton. Olhe que fácil:

var FooSingleton = new function () {
    this.sayHello = function () {
        alert("Hello from a true singleton!");
    };
} ();

FooSingleton.sayHello();

Singleton com JSON

Outra forma bacana de criar um singleton é usando JSON. Observe:

var FooSingleton = {
    name: "",
    sayHello: function () {
        alert("Hello from " + name);
    }
}

FooSingleton.name = "Elemar JR";
FooSingleton.sayHello();

Implementando Herança (com polimorfismo)?! Sim senhor, senhor!

Quer construir uma especialização de uma classe em JavaScript?! É possível. Repare:

var BaseFoo = function () {
    this.name = "";
    this.sayHello = function () {
        alert("Hello from BaseFoo (name = " + this.name + ")");
    };
};

var Foo = function () { };
Foo.prototype = new BaseFoo();
Foo.prototype.constructor = Foo;

var f = new Foo();
f.name = "Elemar JR";
f.sayHello();

Vamos a receita de bolo:

  1. Tenha uma classe base;
  2. Crie uma classe vazia;
  3. Herde as propriedades e métodos da classe base usando uma instância como protótipo;
  4. Redefina o construtor.

Lindo!

Agora, o polimorfismo:

var BaseFoo = function () {
    this.name = "";
    this.sayHello = function () {
        alert("Hello from BaseFoo (name = " + this.name + ")");
    };
};

var Foo = function () { };
Foo.prototype = new BaseFoo();
Foo.prototype.constructor = Foo;
Foo.prototype.sayHello = function () {
    alert("Hello from Foo! (name = " + this.name + ")");
}

var f = new Foo();
f.name = "Elemar JR";
f.sayHello();

Óbvio e simples.

Criando atributos e métodos “privados”

Todos os métodos e atributos que definimos até aqui são públicos. Para garantir um acesso “quase privado” a atributos e propriedades, devemos utilizar a palavra-chave var no lugar de this. Observe:

var Foo = function () {
    var name = "";
    this.getName = function () {
        return name;
    }

    this.setName = function (value) {
        name = value;
    }

    this.sayHello = function () {
        alert("Hello from BaseFoo (name = " + this.getName() + ")");
    };
};

var f = new Foo();
f.setName("Elemar JR");
f.sayHello();

name é privado.

Definindo Namespaces

Ninguém quer poluir o global scope. Esta prática, além de “suja” é perigosa pois o JavaScript não vai dar qualquer warning quando uma variável tiver seu valor substituído de alguma forma.

A solução para este problema é criar uma variável no global scope que atua como um literal (objeto JSON) ou singleton contendo todo o código da aplicação.

Um exemplo simples:

var myNamespace = new function () {
    this.Cool = {
        Foo: function () {
            this.name = "";
            this.sayHello = function () {
                alert("Hello from " + name);
            }
        }
    }
} ();

var foo = new myNamespace.Cool.Foo();
foo.name = "Elemar JR";
foo.sayHello();

Por hoje, era isso!

Alegre

Etiquetado:
Posted in: Sem categoria