javascript avançado

Post on 06-Jun-2015

3.715 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

Javacript Avançado: herança, closures, curry, bind, partes feias, partes ruins

TRANSCRIPT

JAVASCRIPT AVANÇADORicardo Cavalcanti

kvalcanti@gmail.com

Algumas Ferramentas

“Firebug integrates with Firefox to put a wealth of web development tools at your fingertips while

you browse. You can edit, debug, and monitor CSS, HTML, and JavaScript live in any web page!”

http://getfirebug.com

Prototype: introdução

Não é a biblioteca prototype.js Javascript usa protótipos no seu modelo

de objetos O que importa é o que o objeto faz, e não

de quem ele herda Uma função construtora seta seu

prototype no objetos que cria

Prototype: a propriedade prototype

Todo objeto tem uma propriedade prototype

Ao tenta acessar uma propriedade inexistente, javascript busca a propriedade no prototype do objeto E no prototype do prototype...

Prototype: aumentando prototypes

Ao incluir propriedades e funções ao prototype de um construtor, elas são incluidas nos objetos que o construtor produzvar cat = new Cat("Barsik");

Cat.prototype.animal = "cat";Cat.prototype >> {animal: "cat"}cat.animal >> "cat"Cat.prototype.seeADog = function() {

return "I'm "+this.name+". Sshhhhhhh!";}

cat.seeADog() >> "I'm Barsik. Sshhhhhhh!";

Prototype: mudando o prototype

Mudanças no prototype afetam todas as instâncias

var cat = new Cat("Barsik");var cat2 = new Cat("Murzik");

Cat.prototype.animal = "cat";cat.animal >> "cat"cat2.animal >> "cat“

Cat.prototype.animal = "dog";cat.animal >> "dog"cat2.animal >> "dog"

Prototype: propriedades

O objeto pode ter suas próprias propriedades A delegação cuida da prioridadefunction Gadget(/*String*/ name) {

this.name = name;}var iphone = new Gadget("iPhone");Gadget.prototype.name = "none";

iphone.name >> "iPhone"delete iphone.name;iphone.name >> "none"

Prototype: estendendo JS Objects

Podemos estender inclusive os JS Objects

String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, '');

};

“ bla “.trim() >> “bla”

HERANÇA

Herança clássica

Objetos são instancias de classes

Classes herdam de outra classe

Herança prototípica

Não há classes Objetos herdam de objetos Um objeto tem um link para outro objeto No Firefox é __proto__

var newObject = Object(oldObcet)

newObject

__proto__

oldObject

Herança prototípica

var oldObject = { firstMethod: function(){...}, secondMethod: function(){...},};

var newObject = Object(oldObject);

newObject.thirdMethod = function(){...};

var anotherObject = Object(newObject);

anotherObject.thirdMethod();

Herança prototípica

Ao acessar uma propriedade, o interpretador vai primeiro no objeto,

depois busca no protótipo do objeto, ...depois no protótipo do protótipo... Até Object.prototype

foo 2 foo 1

newObject oldObject

Herança prototípica

Mudanças no oldObject serão visíveis no newObject, como já vimos

Mudanças no newObject não alteram o oldObject

foo 2 foo 1

newObject oldObject

Herança pseudoclássica

Com herança prototípica pura, a linguagem deve ter um operador como a função Object Para criar novos objetos utilizando um já

existente

Javascript usa operadores aparentemente clássicos Mas que funcionam prototipicamente

Pseudoclássica

Três mecanismos: Funções Contruturas O operador new O atributo prototype, nas funções

Operador new

function Contructor(){ this.member = ...;}

Contructor.prototype.firstMethod = function(a,b) {...}

Contructor.prototype.secondMethod = function(a,b) {...}

var newObject = new Constructor();

Operador new

new Constructor() retorno um novo objeto ligado ao Constructor.prototype

newObject Constructor.prototype

newObject oldObject

Operador new

A função Contructor() pasa o novo objeto na variável this Para inicizar o novo objeto

newObject Constructor.prototype

prototype

Cada objeto function criado tem um atributo prototype

O prototype tem um atributo constructor, que refencia o objeto function

Outros atributos adicionados no prototype da função serão vistos nos objetos constuídos com ela

É possível criar constantes e métodos par aos objetos

Herança Pseudoclássica

É possível simular herança clássica atribuindo um objeto criado por um constutor como o protótipo de outra

Mas não é exatamente herança clássica

function BiggerConstructor(){};BiggerConstructor.prototype = new

MyContructor()

function SuperClasse(){}

SuperClasse.prototype.hello = function(){alert('super hello')};

function SubClasse(){};SubClasse.prototype = new SuperClasse();SubClasse.prototype.subhello = function(){alert('sub hello')};

var o = new SubClasse();

o.hello();o.subhello();

function SuperClasse(){}

SuperClasse.prototype.name = 'super';

SuperClasse.prototype.hello = function(){alert(this.name)};

function SubClasse(){

this.name = 'sub';

};

SubClasse.prototype = new SuperClasse();

SubClasse.prototype.subhello = function(){alert(this.name)};

var o = new SubClasse();

o.hello();

o.subhello();

CLOSURES

Escopo nas funções

O escopo é definido pelas funções, e não pelos blocos

Funções internas têm acesso às variáveis das funções externas Exceto this e argumentsfunction f (){ var y = 3; var g = function(){ var x = 2+ y; ... }}

E se a função interna durar mais que a função externa?

Closures

Quando a função interna dura mais que a externa, o escopo externo é preservado Isso se chama closure

Um closure simples

var f = function(x){ var m = function(y){ return x * y; } return m;}var dobro = f(2);var triplo = f(3);

alert(dobro(10));alert(triplo(10));

Quando f() é executado, um novo m() é criado

Enquanto m() existir, seu escopo existe, e o do seu ‘pai’ também

Usando closures

Information Hiding Funções com timers Event handlers Callbacks

Clojures: Dados privados

var quo = function (status) { return { get_status: function ( ) { return status; } };};

var myQuo = quo("amazed");alert(myQuo.get_status( ));

Closures: timers

var fade = function (node) {

var level = 1;

var step = function ( ) {

var hex = level.toString(16);

node.style.backgroundColor = '#FFFF' + hex + hex;

if (level < 15) {

level += 1;

setTimeout(step, 100);

}

};

setTimeout(step, 100);

};

fade(document.body);

Closure: event handler

Função que adiciona um event handler para uma lista de nodes. Ao clicar, alerta a ordem do nó.

var add_the_handlers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function (e) { alert(i); } }}; Qual o resultado?

Closure: event handler

Exemplo corretovar add_the_handlers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function (i) { return function (e) { alert(i); }; } (i); }};

CURRY

Curry

Funções são valores É possível combinar uma função com

alguns argumentos e produzir outra funçãovar mult = function (a, b) {return a * b};var duplicar = mult.curry(2);var duplicar = function (b){ retunr 2*b};

Função curry

Curry cria um closure que guarda a função original e seus argumentos para realizar o currying

Quando executada, ela retorna o resultado da função original com os argumentos passados ao curry e os passados a ela

var mult = function (a, b) {return a * b};var duplicar = mult.curry(2);var seis = duplicar(3); //mult.curry(2)(3) >>> 6

Function.prototype.curry = function ( ) { var args = arguments, that = this; return function ( ) { return that.apply(null,

args.concat(arguments)); };}); //PROBLEMA: arguments não é um

array

Função curry: final

Function.prototype.curry = function ( ) { var slice = Array.prototype.slice, args = slice.apply(arguments), that = this; return function ( ) { return that.apply(null,

args.concat(slice.apply(arguments))); };});

Closures: callbacks

var replace = function (el, url){

var callback = function(t){ el.innerHTML = t; }; makeXHR(callback, url); // ajax}

replace (myEl, minhaURL);

Closures : cuidados

Evite criar funções em loops Para evitar closures indesejados

Atenção com o this Mais sobre isso com bind

BIND

This

window.name = "the window object"

function scopeTest() { return this.name}

scopeTest()// -> "the window

object"

var foo = { name: "the foo

object!", otherScopeTest:

function() { return this.name }

}

foo.otherScopeTest()// -> "the foo object!"

Javascript é dinâmica

//atribuindo a função, SEM executá-lawindow.test = foo.otherScopeTest

//chamando a funçãotest() ; // -> "the window object"

Function bind

Eu gostaria de escolher o ‘this’ da minha funçãowindow.test = foo.otherScopeTest.bind(foo);test() // -> "the foo object!"

Function.prototype.bind = function(scope) { var _function = this; return function() { return _function.apply(scope, arguments); }}

PARTES FEIASRicardo Cavalcanti

kvalcanti@gmail.com

Variáveis globais

Todas as coisas são carregadas no mesmo objeto global

var foo = value;window.foo = value;foo=value;

Escopo

Apesar da sintaxe de C Blocos não criam escopo O escopo é sempre da função

Inserção de ;

Há um mecanismo de completar com ; alguns comandos

return { status: true };

return { status: true };

return ;{ status: true };

=

Palavras reservadas

abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with

var method; // okvar class; // illegalobject = {box: value}; // okobject = {case: value}; // illegalobject = {'case': value}; // okobject.box = value; // okobject.case = value; // illegalobject['case'] = value; // ok

Unicode

char em Javascript tem 16bits

Um char unicode são 2 caracteres em javascript

typeof

typeof 98.6 >> ‘number’

typeof null >> ‘object’

my_value === null //melhorif (my_value && typeof my_value === 'object') { // my_value is an object or an array! }

typeof /a/ >> ‘object’ ou ‘function’ depende da implementação

parseInt

Converte um string num integer Para quando vê um não-dígito

parseInt("16") >> 16parseInt("16 mil") >> 16

Se o string começar com 0 é utilizada a base 8parseInt("08") >> 0parseInt("09") >> 0

Parse int pode receber a baseparseInt("08", 10) >> 8

Ponto fllutuante

Javascript usa IEEE Standard for Binary Floating-Point Arithmetic (IEEE 754)

Portanto0.1 + 0.2 !== 0.3

Atenção quando utilizar valores monetários Melhor multiplicar por 100

NaN

Se algum operando for NaN, o resultado da operação será NaN Converter um string em inteiro gera NaN

Porém NaN === NaN // false

Use a função isNaN isNaN(NaN) // true

null e undefined

value = myObject[name]; if (value == null) { alert(name + ' not found.'); } Um erro anula o outro! value é undefined, mas o operador ==

faz o type coersion Cuidado: NaN e undefined são variáveis

globais!

PARTES RUINS

==

'' == '0' // false0 == '' // true0 == '0' // true

false == 'false' // falsefalse == '0' // true

false == undefined // falsefalse == null // falsenull == undefined // true

' \t\r\n ' == 0 // true

with

Para acessar os atributos de um objeto Problemas:

with (obj) { a = b; }

O mesmo queif (obj.a === undefined) { a = obj.b === undefined ? b : obj.b;} else { obj.a = obj.b === undefined ? b : obj.b;}

eval

Evite! Bem como outras formas que recebem

código como string Contrutor de Fuction setTimeout setInterval

Problema de segurança Difícil de checar e de ler

switch Fall Through

Switch-case sem break Fonte de muitos erros, cuidado!

Comandos sem bloco

Sempre use blocos nos comandos

if (ok) t = true;

if (ok) t = true; advance( );

if (ok) { t = true; advance( );}

if (ok) { t = true;}advance( );

vira

parece

Mas naverdade é

Operadores de bits

Os mesmos de java& and| or^ xor~ not>> signed right shift>>> unsigned right shift<< left shift

Convertem para integer e desconvertem Longe do hardware, lentos

Typed Wrappers

Desnecessáriosnew Boolean(false)

Evite o uso de new Boolean, new Number, new String

Também evite new Object e new Array Use {} e []

Para evitar erros

top related