Peculiaridades do JavaScript – (ou O que o JS tem) – O grande equívoco: JavaScript não é Java!



Peculiaridades do JavaScript – (ou O que o JS tem) – O grande equívoco: JavaScript não é Java!

1 0


Palestra-Peculiaridades-do-JavaScript

Minha palestra sobre peculiaridades do JavaScript

On Github leobetosouza / Palestra-Peculiaridades-do-JavaScript

Peculiaridades do JavaScript

(ou O que o JS tem)

Leonardo Alberto Souza (@leobetosouza)

Quem sou eu?

  • Viciado em computadores e internet desde pequeno
  • Cursei 3 anos de Ciência da Computação e hoje faço Sistemas de Informação na UFF
  • Trabalho como Desenvolvedor Front-end há 6 anos
  • Sou um dos administradores do rio.js e participo de diversos grupos relacionados à JS e desenvolvimento web

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.

O grande equívoco: JavaScript não é Java!

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

O que JavaScript é?

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.

- Wikipedia

Tipagem: Dinâmica e Fraca

  • O tipo das variaveis é definido em tempo de execução (como Ruby, Perl, Python, Groovy, PHP e Lisp)
  • O tipo da variavel pode mudar (como Perl, PHP, Visual Basic e AppleScript)

Em Linguagens estritas e de tipagem forte isso aqui vai causar erros:

var x = 1;
typeof x; // 'number'

x = '';
typeof x; // 'string'
						

Como saber se a variavel é do tipo que eu quero?

// 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 ;)

Igualdade, Verdade e Falsidade

=== vs. ==

=== e !== testam se os valores tem o mesmo tipo, então...

1 == '1' // true
1 === '1' // false
'1' !== 1 // true
'1' != 1 // false
						

Verdade e Falsidade

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') :)

A mágica do 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

						

Esta peculiaridade é muito usada para lidar com prefixos de navegadores

window.requestFullScreen = window.requestFullScreen || window.mozRequestFullScreen || window.webkitRequestFullScreen;
						

O and (&&) também trabalha de forma parecida:

"gato" && "cachorro" // "cachorro"
false && 10 // false

						

Escopo e Hosting de Variaveis

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

}
						

Cuidado com globais implicitas!

function doSomething() {
	x = 10;
}
function doOtherThing() {
	var y = 10;
}

doSomething();
doOtherThing();
console.log( x ); // 10
console.log( y ); // ReferenceError: y is not defined

						

Objects e Arrays

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]

						

Funções

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ção de Função vs. Expressão de Função

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 );
    }
  };

})();
						

Argumentos

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
						

Sobrecarga

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;
	}
} 
						

Exemplo em C++

Referências

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.

Artigos

Bons artigos que li enquanto e antes de fazer essa apresentação:

Livros

São os livros que eu li e mais aprendi:

Blogs

Existem muitos outros blogs bons, mas esses são os que eu recomendo pra quem tá aprendendo:

Obrigado! ;)

Leonardo Alberto Souza (@leobetosouza)

Dúvidas, correções e sugestões são sempre bem-vindas.Gostou?

Tweetar