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