On Github leobetosouza / Palestra-Peculiaridades-do-JavaScript
JavaScript é uma linguagem bem fácil de aprender, mas tão difícil de dominar quanto a maioria das linguagens de programação.
Ela também é bastante odiada por diversos programadores, talvez por não conhecerem-na bem.
Esta apresentação visa mostrar um pouco daquilo que JavaScript tem de diferente e resolver alguns dos erros e enganos comuns.
JavaScript foi batizada pelo seu criador, Brendan Eich, como LiveScript. Na época Java era uma nova e emergente tecnologia que já estava aparecendo nos browsers. A Netscape achou que seria uma boa ideia pegar uma carona e colocou Java no nome.
As pessoas passaram a achar que JavaScript era um Java mais limitado, ou um Java para o browser. Mas a verdade é que JS e Java têm bem pouco em comum...
- The World's Most Misunderstood Programming Language - Douglas Crockford
Em Linguagens estritas e de tipagem forte isso aqui vai causar erros:
var x = 1; typeof x; // 'number' x = ''; typeof x; // 'string'
// String: typeof variable === "string" // Number: typeof variable === "number" // Boolean: typeof variable === "boolean" // Object: typeof variable === "object" // Function: typeof variable === "function" // Array: Array.isArray(arrayObject)
typeof é um operador ;)
=== e !== testam se os valores tem o mesmo tipo, então...
1 == '1' // true 1 === '1' // false '1' !== 1 // true '1' != 1 // false
ou nem tudo que parece verdade é...
if ("teste") {
console.log("teste" == false); // false
console.log("teste" == true); // false
console.log("teste" === false); // false
console.log("teste" === true); // false
}
A conversão para boolean usada em um if (ou no construtor Boolean()) segue a seguinte regra:
false, '', 0, NaN, null e undefined são falsos, o resto é verdadeiro.
Boolean([]); // true
Boolean([false]); // true
Boolean('false'); // true
Boolean(false); // false
Boolean(0); // false
Recomendo ler: Uma explicação longa e detalhada sobre o assunto
Por favor, não use Boolean() nos seus códigos, nem if ('teste') :)
O operador || funciona de maneira um pouco diferente do que se espera.
var x = 0 || 1; console.log( x ); // 1
O valor "retornado" do operador lógico or, diferentemente do que pode-se esperar, não é necessáriamente um booleano.
Mas ele retorna o primeiro valor verdadeiro da expressão, ou o último valor caso nenhum seja verdadeiro.
"" || false || 0 || "casa" // "casa"
0 || true || 20 // true
10 || true // 10
undefined || {} // {}
null || undefined || 0 // 0
window.requestFullScreen = window.requestFullScreen || window.mozRequestFullScreen || window.webkitRequestFullScreen;
O and (&&) também trabalha de forma parecida:
"gato" && "cachorro" // "cachorro" false && 10 // false
JavaScript só tem dois escopos: global e de função
var vogais = ['a', 'e', 'i', 'o', 'u'];
for (var i = 0; i < vogais.length; i++) {
var x = 10;
}
console.log( i ); // 4
console.log( x ); // 10
A declaração da variavel é hasteada ao topo do escopo, mas a atribuição não:
function doSomething() {
var x = 10;
console.log( y ); // undefined
console.log( z ); // undefined
( ... )
if ( true ) {
var y = 5;
}
var z = x + 5;
console.log( y ); // 5
console.log( z ); // 15
}
function doSomething() {
x = 10;
}
function doOtherThing() {
var y = 10;
}
doSomething();
doOtherThing();
console.log( x ); // 10
console.log( y ); // ReferenceError: y is not defined
Tudo em JavaScript é, ou pode ser manipulado como, um objeto
var numero = 123; numero.toExponential(); // '1.23e+2' var bool = false; bool.toString(); // 'false' var vogais = [ 'a', 'e', 'i', 'o', 'u' ]; typeof vogais; // 'object'
Os tipos primitivos (number, string e boolean) não são objetos, mas são convertidos para seus respectivos objetos em tempo de execução quando necessário.
Somente com undefined e null isso não acontece.
String instanceof Object; //true Array instanceof Object; //true Number instanceof Object; //true Function instanceof Object; //true
instanceof também é um operador ;)
Você pode usar o construtor ou o object literal, mas cuidado com Arrays
var objeto1 = new Object();
var objeto2 = {};
var vetor1 = new Array( 1, 2, 3 );
// [1 , 2, 3]
var vetor2 = new Array( 3 );
// [ , , ] WTF?
var vetor3 = [ 1, 2, 3 ];
// [ 1, 2, 3 ]
var vetor4 = [ 3 ];
// [ 3 ]
Cuidado na hora de retornar Object Literals de uma função
funtion foo() {
return
{
param: 1
};
}
var bar = foo();
console.log( bar.param );
// TypeError: Cannot read property 'param' of undefined
O ASI (Automatic Semicolon Insertion) insere um ponto-e-virgula após o return e a função retorna undefined
funtion foo() {
return {
param: 1
};
}
var bar = foo();
console.log( bar.param );
// 1
JS não tem classes. Herança é prototipal:
function Collection(){}
Collection.prototype = new Array();
var c = new Collection();
c.push( 1 );
c.push( 2 );
c.push( 3 );
console.log( c );
// { '0': 1, '1': 2, '2': 3, length: 3 }
c instanceof Collection; // true
c instanceof Array; // true
c instanceof Object; // true
Collection.prototype.sum = function() {
var cont = 0;
this.forEach(function(x){
cont+=x;
});
return cont;
};
c.sum();
// 6
typeof Array.prototype.sum; // 'undefined'
typeof Collection.prototype.sum; // 'function'
Cuidado ao iterar em objetos e arrays:
for ( prop in c ) {
console.log( prop );
}
// 0, 1, 2, length, sum
for ( prop in c ) {
console.log( c[prop] );
}
// 1, 2, 3, 3, [Function]
No JavaScript funções são objetos de primeira classe.
O seja: elas podem ter métodos e propriedades, podem ser atribuídas à variaveis, criadas em tempo de execução e podem ser passadas como parâmetros e retornadas de/para outras funções.
function somar( a, b ) {
return a + b;
}
function multiplicar ( a, b ) {
return a * b;
}
function criarFuncao( func, n ) {
return function ( x ) {
return func( n, x );
};
}
var soma1 = criarFuncao( somar, 1 );
var mult2 = criarFuncao( multiplicar, 2 );
soma1(2); // 3
mult2(6); // 12
Funções criam closures. Ou seja: elas tem acesso as variaveis do escopo em que foram criadas
function criarContador() {
var x = 0;
return function () {
return ++x;
};
}
var contA = criarContador();
var contB = criarContador();
contA(); // 1
contA(); // 2
contA(); // 3
contB(); // 1
Declarações de Função são hasteadas
foo(); // true
bar(); // TypeError: bar is not a function
function foo(){return true;};
var bar = function(){return true;};
Expressões de Função podem ser auto-executadas
var a = (function(){
return 10;
}());
console.log( a ); // 10
Expressões de Função são funções anônimas
function teste1(){}
var teste2 = function(){};
console.log( teste1.name ); // 'teste1'
console.log( teste2.name ); // ''
Funções Anônimas Auto-executáveis são um pattern comum para criar escopo local
(function($){
// pode usar o objeto $ com segurança
}(jQuery));
O Module Pattern usa closures numa função anônima para criar métodos privados
var myNamespace = (function () {
var myPrivateVar = 0;
var myPrivateMethod = function( foo ) {
console.log( foo );
};
return {
myPublicVar: "foo",
myPublicFunction: function( bar ) {
// Increment our private counter
myPrivateVar++;
// Call our private method using bar
myPrivateMethod( bar );
}
};
})();
function soma ( a, b ) {
return a + b;
}
soma( 2, 2 ); // 4
soma( 3 ); // NaN
Parametros com valores padrões
function soma ( a, b ) {
b = b || 0;
return a + b;
}
soma( 3 ); // 3
Número infinito de argumentos
function soma() {
var i;
var cont = 0;
for ( i = 0; i < arguments.length; i++ ) {
cont += arguments[i];
}
return cont;
}
soma( 3, 3, 3 ); // 9
Cuidado: arguments NÃO é um Array!
Mas pode ser transformado em um:
function soma() {
var args = Array.prototype.slice.call( arguments );
var cont = 0;
args.forEach(function( x ){
cont += x;
});
return cont;
}
soma( 2, 2, 2, 2 ); // 8
Definir a mesma funcão varias vezes, sobescreve a funcão anterior
function volume( s ) {
// volume of a cube
return s * s * s;
}
function volume( r, h ) {
// volume of a cylinder
return 3.14 * r * r * h;
}
function volume( l, b, h ) {
// volume of a cuboid
return l * b * h;
}
volume( 3 ); // NaN
uma maneira de fazer function overloading em JS é tratando os argumentos:
function volume() {
var s, r, h, b, l;
if ( arguments[1] === undefined ) {
// volume of a cube
s = arguments[0];
return s * s * s;
}
if ( arguments[2] === undefined ) {
// volume of a cylinder
r = arguments[0];
h = arguments[1];
return 3.14 * r * r * h;
}
if ( arguments[3] === undefined ) {
// volume of a cuboid
l = arguments[0];
b = arguments[1];
h = arguments[2];
return l * b * h;
}
}
Web Platform são uma referencia feita em conjunto entre Google, Mozilla, Microsoft, Opera, Adobe e muitos que apoiam a Open Web. MDN, até a Web Platform, era a melhor referência de JavaScript. Idiomatic.js é um guia de estilo com várias dicas boas. Eloquent JavaScript é o melhor e mais divertido livro pra aprender JS e tem uma versão em HTML online. E o livro de Patterns do Addy Osmani é muito bom e também está à venda em papel.
Bons artigos que li enquanto e antes de fazer essa apresentação:
São os livros que eu li e mais aprendi:
Existem muitos outros blogs bons, mas esses são os que eu recomendo pra quem tá aprendendo:
Dúvidas, correções e sugestões são sempre bem-vindas.Gostou?
Tweetar