JavaScript é uma linguagem dinâmica que possui várias peculiaridades e por isso requer uma maneira diferente de pensar e solucionar problemas.
Metodologias adotadas em outros contextos podem não ser os mais indicadas e por isso é importante refletir antes de copiar paradigmas enraizados em outras linguagens.
Senta que lá vem história...
comecei a "programar" em 1999 usando o FrontPage.
em 2005 falei que nunca aprenderia JavaScript.
em 2006 lancei meu primeiro projeto open-source escrito em JavaScript (swffit).
hoje em dia sou Senior Developer na Firstborn e escrevo milhares de linhas de JS todo mês.
Como isso aconteceu?
JavaScript se tornou a linguagem mais importante da Web e hoje em dia é também a linguagem com o maior número de usuários.
Aprendi (a amar) JavaScript.
Indo com a correnteza
Composição > Herança
Quando herança é a única ferramenta que você conhece todos os problemas se parecem filhos de outros problemas.
Antigamente eu provavelmente faria algo do tipo:
function ZoomControl(){
VerticalSlider.call(this);
...
}
ZoomControl.prototype = Object.create(VerticalSlider.prototype);
Hoje em dia é mais comum eu fazer:
function ZoomContol(){
this._slider = new VerticalSlider();
this._buttons = new IncrementButtons();
...
}
Duck typing
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
— Se parece um pato, é um pato.
Ao invés de escrever:
function process(foo)
if (foo.constructor === Dolor) {
foo.amet();
} else if (foo instanceof Bar) {
doSomething(foo.bar);
}
...
}
Escrevo*:
function process(foo) {
if (typeof foo.amet === 'function') {
foo.amet();
} else if ('bar' in foo) {
doSomething(foo.bar);
}
...
}
PS: use typeof somente para "string", "number" e "function" !! typeof null == "object"
Na verdade mesmo escreveria:
function processFoo(foo) {
foo.amet();
sharedProcess(foo);
}
function processBar(foo) {
doSomething(foo.bar);
sharedProcess(foo);
}
function sharedProcess(foo) {
// ...
}
WTFJS
Evite usar construtores para String, Number e Array.
var lorem = 'ipsum'; // `lorem` é global
// iife cria um "closure" (escopo local)
(function(){
var foo = 'bar'; // `foo` é "local"
console.log(lorem); // 'ipsum'
console.log(foo); // 'bar'
}());
console.log(lorem); // 'ipsum'
// ReferenceError: foo is not defined
console.log(foo);
Flexibilidade é uma das maiores virtudes do JavaScript.
// salva referência do método original
var originalOnAdd = ClusterIcon.prototype.onAdd;
// sobrescreve método
ClusterIcon.prototype.onAdd = function () {
if (! this.shadow_) {
this.shadow_ = document.createElement('div');
this.getPanes()
.overlayShadow
.appendChild(this.shadow_);
}
// executa método original no "contexto" this
originalOnAdd.apply(this, arguments);
};
Também uso as funções como uma maneira de forçar com que os erros sejam identificados rapidamente, já que um erro é disparado ao chamar um método inexistente.
Como JavaScript possui higher-order functions e execução de métodos raramente acarreta problemas de performance eu passei a adotar vários conceitos de programação funcional no meu código.
Ao invés de escrever:
var user;
var hipsters = [];
for (var i = 0; i < users.length; i++) {
user = users[i];
if (user.isHipster) {
hipsters.push(user);
}
}
doSomething(hipsters);
Escrevo:
var hipsters = filter(users, function(user){
return user.isHipster;
});
doSomething(hipsters);