Back-End

26 abr, 2011

JavaScript para desenvolvedores PHP

Publicidade

Espero
que você tenha sido um bom nerd em 2010 e tenha aprendido JavaScript. Agora, vamos rebater com uma taça de vinho ao lado da
lareira e revisar o que você aprendeu. 

Objetos

Quase
tudo em JavaScript é um objeto, mas não existem classes. Uma maneira de
definir um objeto é simplesmente listar as propriedades que você quer que
o objeto tenha, separá-las por vírgulas e envolvê-las em colchetes ondulados:

var calendar = { 
name: "PHP Advent",
year: 2010
};

Esse
simples objeto não tem nenhum método e se parece mais com uma matriz associativa
do PHP. Na verdade, o JavaScript não tem matrizes associativas e usa objetos em
seu lugar. Para criar um objeto semelhante no PHP, você pode converter uma
matriz em um objeto:

$calendar = (object) array( 
name => 'PHP Advent',
year => 2010
);

Simples,
não? Nenhuma classe à vista. Objetos não são nada mais do que matrizes
elaboradas. Elaboradas porque alguns elementos da matriz são invocáveis, e nós
os chamaremos de métodos.

Uma outra
abordagem para criar objetos é começar com um objeto “vazio”.

var calendar = {};

Isso é
exatamente como $calendar = new stdClass(); em PHP. Em JS, você pode também
fazer var calendar = new Object(); mas isso é apenas um exercício de digitação.

Você pode
adicionar outras coisas (propriedades e métodos) pelo caminho:

calendar.name = "PHP Advent"; 
calendar.year = 2010;
calendar.say = function () {
return this.name + ' ' + this.year;
};

Como
você pode ver, o JavaScript usa . em vez de -> para acessar
propriedades e métodos.

calendar.say(); // returns "PHP Advent 2010"

Posso ter classes?

Não
existem classes no JavaScript, mas se você realmente sente falta delas,
existem as constructor functions.

function Calendar(year) { 
this.name = "PHP Advent";
this.year = year;
this.say = function () {
return this.name + ' ' + this.year;
};
}

Constructor
functions
são funções normais, mas quando chamadas com new, elas retornam como
objetos.

var thisyear = new Calendar(2010), 
lastyear = new Calendar(2009);
thisyear.say(); // "PHP Advent 2010"

O
equivalente em PHP seria algo como:

class Calendar { 
public $name = 'PHP Advent';
public $year;

function __construct($year) {
$this->year = $year;
}

function say() {
return $this->name . ' ' . $this->year;
}
}

$thisyear = new Calendar(2010);
$lastyear = new Calendar(2009);

echo $thisyear->say(); // "PHP Advent 2010"

Constructor
functions versus funções normais

A maneira
como você define uma constructor function no JavaScript é a mesma que
você usa para uma função normal. A diferença é a invocação. Quando chamada
com new, uma função sempre retorna como objeto. Se você não fizer nada de
especial, o objeto referido por ela será retornado.

alert(typeof new Calendar()); // "object"

Quando
chamadas sem new, as funções retornam para onde quer que a declaração de
retorno esteja no corpo da função. Se não existe um retorno explícito, a função
vai retornar o value undefined especial.

alert(typeof Calendar()); // "undefined"

Com o
objetivo de distinguir a intenção de uma função ao ler um código, existe uma
convenção generalizada de nomear as constructor functions com a primeira letra
em caixa alta.

function MyConstructor() {} 
function myFunction() {}

Funções
são objetos

No
JavaScript, em que a maioria das coisas são objetos, funções são objetos também.
Eles podem (e têm) propriedades e métodos. Você provavelmente vai ver funções
definidas com var, desta maneira:

var sum = function (a, b) { 
return a + b;
};

Agora,
olhe isto aqui:

alert(sum.length); // 2

O que é
isso? Nós acessamos a propriedade length do sum do objeto. Objetos de função
têm uma propriedade length que contém o número de parâmetros que eles aguardam
(mas não os imponha, já que todos os parâmetros têm um valor padrão
indefinido), nesse caso, dois: a e b.

Prototype

Funções
são objetos, e eles automaticamente geram uma propriedade chamada prototype.
Essa propriedade é usada quando um objeto é criado utilizando uma constructor
function
. O prototype também é um objeto (surpresa, surpresa).

function Calendar(year) { 
this.year = year;
}

Calendar.prototype.name = "PHP Advent";

Calendar.prototype.say = function () {
return this.name + ' ' + this.year;
};

var thisyear = new Calendar(2010);
thisyear.say(); // "PHP Advent 2010"

Aqui, nós
temos um comportamento que é muito parecido com o antigo constructor Calendar
que criamos. O Objeto thisyear tem acesso a say() como se fosse seu próprio
método, mas ele aparece transparentemente via prototype.

Como as
propriedades adicionadas ao PROTOTYPE são compartilhadas e reutilizadas entre
todos os objetos calendar, este é o lugar para colocar todas as peças de
funcionalidade reusáveis. É uma prática comum colocar todos os métodos aqui.

Prototypes
também disponibilizam maneiras de implementar o código reuse (inheritance).

Você provavelmente
irá notar que eu disse objetos “vazios” no início deste artigo.
Eu os adicionei porque não existe algo como um objeto em branco. Todos os
objetos vêm com alguns métodos e propriedades pré-existentes, herdadas da prototype
chain
.

Funções
anônimas

Muitas
vezes, você precisa de uma função one-off que não precisa de nome, ou funções
que você pretende passar para outras funções como callbacks. Você pode usar
funções anônimas nesses casos.

No
JavaScript, existe apenas uma função scope – qualquer variável definida que não
seja a fonte é um global. Isso não é, obviamente, desejado, porque mais globals
significam um maior risco de colisões de nomes.

Um padrão
comum para reduzir o número de variáveis temporárias dispersas por
aí é envolver peças de código independentes em uma immediate function,
o que significa uma função anônima que é executada imediatamente.  

// Alerts 3 and leaves no leftover variables. 
(function () {

var a = 1,
b = 2;

alert(a + b);

}());

No PHP,
funções anônimas têm estado disponíveis desde o lançamento da versão 5.3, e
você pode invocá-las com call_user_func(), então o equivalente seria: 

call_user_func(function() { 
$a = 1;
$b = 2;
echo $a + $b;
});

Ou no
PHP, antes do 5.3:

call_user_func(create_function('', 
'$a = 1;
$b = 2;
echo $a + $b;'
));

Arrays

Arrays
são simplesmente listas de valor delimitadas por vírgulas envolvidas por
colchetes.

var dudes = ['Ilia', 'Andrei', 'Derick']; 
alert(dudes[2]); // "Derick"

// Ou, se você quiser digitar mais:
var dudes = new Array('Ilia', 'Andrei', 'Derick');

No PHP,
isso é igual:

$dudes = array('Ilia', 'Andrei', 'Derick'); 
echo $dudes[2]; // "Derick"

Mas eis
que Arrays são objetos também, então, em vez de passar o Array para uma função
para conseguir o seu tamanho, você pode acessar sua propriedade length. 

// JS 
alert(dudes.length); // 3

// PHP
echo count($dudes); // 3

Pushes,
pops e diversos flip-flops também compartilham um comportamento similar no PHP
e no JavaScript.

// JS 
dudes.pop(); // returns "Derick"
dudes.toString(); // "Ilia,Andrei"
dudes.push('Rasmus'); // returns 3, the new size
dudes.toString(); // "Ilia,Andrei,Rasmus"

// PHP
array_pop($dudes);
echo implode(',', $dudes);
array_push($dudes, 'Rasmus');
echo implode(',', $dudes);

A sintaxe
preguiçosa e conveniente do PHP para anexar a um Array ($dudes[] = ‘Ben’;) não
está disponível em JavaScript. Você precisa saber o tamanho ou conhecer o Array (para saber
o índice do último elemento), para que você possa usar

 dudes[dudes.length] = 'Ben'; 

// dudes.push('Ben') é grosseiramente equivalente ao append operator do PHP.

O
mplode() e o explode() do PHP se transformam em join() e split() no JavaScript.

// PHP 
$a = explode(',', '1,2,3');
echo implode(', then ', $a); // "1, then 2, then 3"

// JS
var a = "1,2,3".split(',');
alert(a.join(', then ')); // "1, then 2, then 3"

Strings

Não
existe nada muito excitante sobre strings, a não ser – você adivinhou –
que strings são objetos também. Bem, tecnicamente, existe uma diferença entre um
string object e uma primitive string, mas estas últimas são
convertidas para objetos quando necessário, então não há necessidade de se
preocupar com os detalhes. 

// string object 
var so = new String('Crocodile');
alert(typeof s); // "object"

// primitive string
var sp = 'Alligator';
alert(typeof s); // "string"

// But, primitives do behave like objects.
alert("dude".length); // 4

Assim
como com Arrays, todas as suas funções de manipulações favoritas de string se
tornam uma variedade de métodos. 

// JS 
var s = "PHP Advent";
alert(s.substring(6)); // "vent"
alert(s.replace(' ', 'eeee')); // "PHPeeeeAdvent"
alert(s.replace(' ', 'eeee').substring(0, 7)); // "PHPeeee"

// PHP
$s = 'PHP Advent';
print(substr($s, 6)); // "vent"
print(str_replace(' ', 'eeee', $s)); // "PHPeeeeAdvent"
print(substr(str_replace(' ', 'eeee', $s), 0, 7)); // "PHPeeee"

Callbacks

O último
tópico antes de encerrarmos, callback functions. Elas ilustram dois dos
conceitos que já falamos aqui, funções e Arrays.

Uma
maneira legal de criar funções e métodos reutilizáveis é fazer com que
eles aceitem outras funções como parâmetros, que são conhecidas como callback
functions.

Um bom
exemplo para isso está no método sort() de objetos de Arrays no
JavaScript. Esse método aceita um callback assim como o usort() no PHP.

No
JavaScript, se você quiser uma classificação numérica, precisa
disponibilizar um callback; não existe nenhuma flag como sort() no PHP.

// JS 
var a = [2, 1, 30, 15];
a.sort(); // "1, 15, 2, 30", not what you expect

// PHP
$a = array(2, 1, 30, 15);
sort($a); // "1, 2, 15, 30", a.k.a., the right thing

// PHP like JS
$a = array(2, 1, 30, 15);
sort($a, SORT_STRING); // "1, 15, 2, 30"

Quer uma
classificação numérica? Passe uma callback function:

// anonymous callback 
var a = [2, 1, 30, 15];
a.sort(function (a, b) {
return (a > b) ? 1 : -1;
});
// "1, 2, 15, 30"

//Ou forneça uma função existente como callback.
var a = [2, 1, 30, 15];

function numsort(a, b) {
return (a > b) ? 1 : -1;
}

a.sort(numsort); // "1, 2, 15, 30"

Se
você fosse fazer o mesmo tipo de callback no PHP (não que
você precise fazer para classificação numérica, mas é uma ilustração),
você pode fornecer também um callback anônimo ou uma função existente:

// anonymous callback (PHP 5.3) 
$a = array(2, 1, 30, 15);
usort($a, function ($a, $b) {
return ($a > $b) ? 1 : -1;
});

// existing function as a callback (PHP 4+)
$a = array(2, 1, 30, 15);

function numsort ($a, $b) {
return ($a > $b) ? 1 : -1;
};

usort($a, 'numsort');

Finalizando

JavaScript
e PHP são bastante similares; eles compartilham a sintaxe C-likex, com
colchetes ondulados, funções, ifs, for loops, &c. Mesmo assim, o JavaScript
tem algumas especificidades, como:

  • sem classes
  • a maioria das coisas são objetos,
    incluindo arrays e strings
  • funções são objetos
  • funções fornecem um scoping
    variável
  • constructor functions
  • prototypes

Na
maioria das vezes, quando as pessoas dizem que odeiam JavaScript, elas querem
dizer que elas odeiam os DOM APIs bugados e inconsistentes fornecidos pelos
browsers. Despido, o JavaScript (ou ECMAScript) é uma linguagenzinha linda,
como diriam alguns, que vale a pena aprender. Ela
não tem o excelente manual que tem o PHP, com todas as imensuráveis notas dos
usuários (e quem tem?), mas existe uma referência do Mozilla para seu prazeroso bookmarking.

Esta
é para as horas felizes “JavaScriptando” em 2011!


?

Texto original disponível em http://phpadvent.org/2010/javascript-for-php-developers-by-stoyan-stefanov