Dotstore
Canais iMasters

PHP + Javascript

JavaScript para desenvolvedores PHP

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

Stoyan Stefanov

Stoyan Stefanov

é búlgaro e já trabalhou no Yahoo! e no SAP Canadá. É o criador do otimizador de imagem do Smush.it e da ferramenta de performance YSlow 2.0. Atualmente, trabalha como engenheiro no Facebook.


Comente também

10 Comentários

Walter Wolseley Lima
Walter Wolseley Lima

Simplesmente excelente!
Matéria muito interessante para quem está tentando mesclar ambas linguagens!

Felipe Girotti
Felipe Girotti

Muito boa esta matéria, esclareceu muitas dúvidas minhas.

"colchetes ondulados" a.k.a. chaves..
=]

Trambulhao Trambolho
Trambulhao Trambolho

Parabéns..

Gustavo
Gustavo

Gostei do "colchetes ondulados"...rs
Mto show o artigo!

@R4bugento
@R4bugento

Muito legal mesmo a matéria, tem uma abordagem muito boa. Gosto de JS =), inclusive estou estudando nodejs que já é um outro paradigma.

Abraços

Ingmar Aguiar
Ingmar Aguiar

Muito boa a matéria. Parabéns.

Douglas Miranda
Douglas Miranda

Escolheu um ótimo artigo para traduzir, tinha lido, mas é muito bacana para quem não tem afinidade com o inglês, também aprender!

Marlon Wanger
Marlon Wanger

Gostei , gostei , otimo conteudo.

Qual a sua opinião?

Comentários considerados ofensivos serão moderados.
BlackBerry

Parceiros

IBM
Abril
Hostmídia
PagSeguro
Impacta
Internet Innovation
Grupo Buscapé
Dialhost
O Ligador
RedeHost
Campus Party
Apiki
Tecla
Verisign
KingHost
DotStore
Café Azul - Social, Mobile e Smart TV
WebMatrixWebMatrix