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...
JavaScript's C-like syntax, including curly braces and the clunky for
statement, makes it appear to be an ordinary procedural language. This is misleading because JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java. It has arrays instead of lists and objects instead of property lists. Functions are first class. It has closures. You get lambdas without having to balance all those parens.
- The World's Most Misunderstood Programming Language - Douglas Crockford
JavaScript (sometimes abbreviated JS) is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions. It is a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles.
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 ;)
===
vs. ==
===
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')
:)
or
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?