Javascript avançadoRicardo Cavalcantikvalcanti@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çãoNão é a biblioteca prototype.jsJavascript usa protótipos no seu modelo de objetosO que importa é o que o objeto faz, e não de quem ele herdaUma função construtora seta seu prototype no objetos que cria
Prototype: a propriedade prototypeTodo objeto tem uma propriedade prototypeAo tenta acessar uma propriedade inexistente, javascript busca a propriedade no prototype do objetoE no prototype do prototype...
Prototype: aumentando prototypesAo incluir propriedades e funções ao prototype de um construtor,  elas são incluidas nos objetos que o construtor produzvar cat = newCat("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'mBarsik. Sshhhhhhh!";
Prototype: mudando o prototypeMudanças no prototype afetam todas as instânciasvar cat = newCat("Barsik");var cat2 = newCat("Murzik");Cat.prototype.animal = "cat";cat.animal >> "cat"cat2.animal >> "cat“Cat.prototype.animal = "dog";cat.animal >> "dog"cat2.animal >> "dog"
Prototype: propriedadesO objeto pode ter suas próprias propriedadesA delegação cuida da prioridadefunctionGadget(/*String*/ name) {this.name = name;}var iphone = newGadget("iPhone");Gadget.prototype.name = "none";iphone.name >> "iPhone"delete iphone.name;iphone.name >> "none"
Prototype: estendendo JS ObjectsPodemos estender inclusive os JS ObjectsString.prototype.trim = function(){	return this.replace(/^\s+|\s+$/g, ''); };“  bla  “.trim() >> “bla”
Herança
Herança clássicaObjetos são instancias de classesClasses herdam de outra classe
Herança prototípicaNão há classesObjetos herdam de objetosUm objeto tem um link para outro objetoNo Firefox é __proto__var newObject = Object(oldObcet)newObjectoldObject__proto__
Herança prototípicavar oldObject = {firstMethod: function(){...},secondMethod: function(){...},};var newObject = Object(oldObject);newObject.thirdMethod = function(){...};var anotherObject = Object(newObject);anotherObject.thirdMethod();
Herança prototípicaAo 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.prototypenewObjectoldObjectfoo2foo1
Herança prototípicaMudanças no oldObject serão visíveis no newObject, como já vimosMudanças no newObject não alteram o oldObjectnewObjectoldObjectfoo2foo1
Herança pseudoclássicaCom herança prototípica pura, a linguagem deve ter um operador como a função ObjectPara criar novos objetos utilizando um já existenteJavascript usa operadores aparentemente clássicosMas que funcionam prototipicamente
PseudoclássicaTrês mecanismos:Funções ContruturasO operador newO atributo prototype, nas funções
Operador newfunctionContructor(){this.member = ...;}Contructor.prototype.firstMethod = function(a,b) {...}Contructor.prototype.secondMethod = function(a,b) {...}var newObject = newConstructor();
Operador newnewConstructor() retorno um novo objeto ligado ao Constructor.prototypenewObjectoldObjectnewObjectConstructor.prototype
Operador newA função Contructor() pasa o novo objeto na variável thisPara inicizar o novo objetonewObjectConstructor.prototype
prototypeCada objeto function criado tem um atributo prototypeO prototype tem um atributo constructor, que refencia o objeto functionOutros 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 outraMas não é exatamente herança clássicafunction BiggerConstructor(){};BiggerConstructor.prototype = new MyContructor()
functionSuperClasse(){}SuperClasse.prototype.hello = function(){alert('super hello')};functionSubClasse(){};SubClasse.prototype = newSuperClasse();SubClasse.prototype.subhello = function(){alert('sub hello')};var o = newSubClasse();o.hello();o.subhello();
functionSuperClasse(){}SuperClasse.prototype.name= 'super';SuperClasse.prototype.hello= function(){alert(this.name)};functionSubClasse(){this.name = 'sub';};SubClasse.prototype = newSuperClasse();SubClasse.prototype.subhello = function(){alert(this.name)};var o = newSubClasse();o.hello();o.subhello();
Closures
Escopo nas funçõesO escopo é definido pelas funções, e não pelos blocosFunções internas têm acesso às variáveis das funções externasExceto 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?
ClosuresQuando a função interna dura mais que a externa, o escopo externo é preservadoIsso se chama closure
Um closure simplesvar f = function(x){  var m = function(y){returnx * y;  }return m;}var dobro = f(2);var triplo = f(3);alert(dobro(10));alert(triplo(10));Quando f() é executado, um novo m() é criadoEnquanto m() existir, seu escopo existe, e o do seu ‘pai’ também
Usando closuresInformationHidingFunções com timersEventhandlersCallbacks
Clojures: Dados privados var quo = function (status) {return {get_status: function (  ) {return status;        }    };};var myQuo = quo("amazed");alert(myQuo.get_status( ));
Closures: timersvar 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: eventhandlerFunção que adiciona um eventhandler 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: eventhandlerExemplo corretovar add_the_handlers = function (nodes) {    var i;    for (i = 0; i < nodes.length; i += 1) {nodes[i].onclick = function (i) {returnfunction (e) {alert(i);            };}  (i);    }};
Curry
CurryFunçõ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 curryCurry  cria um closure queguarda a função original e seusargumentospararealizar o curryingQuandoexecutada, elaretorna o resultadodafunção original com osargumentospassadosao curry e ospassados a elavar mult = function (a, b) {return a * b};var duplicar = mult.curry(2);varseis = duplicar(3); //mult.curry(2)(3) >>> 6
Function.prototype.curry = function (  ) {varargs = arguments, that = this;    return function (  ) {        return that.apply(null, args.concat(arguments));    };}); //PROBLEMA: arguments não é um array
Função curry: finalFunction.prototype.curry = function(  ) {    var slice = Array.prototype.slice,args = slice.apply(arguments),that = this;returnfunction (  ) {returnthat.apply(null, args.concat(slice.apply(arguments)));    };});
Closures: callbacksvar replace = function (el, url){   var callback = function(t){el.innerHTML = t;   };makeXHR(callback, url); // ajax}replace (myEl, minhaURL);
Closures: cuidadosEvite criar funções em loopsPara evitar closures indesejadosAtenção com o thisMais sobre isso com bind
bind
Thiswindow.name= "thewindowobject"functionscopeTest() {returnthis.name}scopeTest()// -> "thewindowobject"var foo = {name: "thefooobject!",otherScopeTest: function() { returnthis.name }}foo.otherScopeTest()// -> "thefooobject!"
Javascript é dinâmica//atribuindo a função, SEM executá-lawindow.test= foo.otherScopeTest//chamando a funçãotest() ; // -> "the window object"
FunctionbindEu gostaria de escolher o ‘this’ da minha funçãowindow.test = foo.otherScopeTest.bind(foo);test() // -> "thefooobject!"Function.prototype.bind = function(scope) {  var _function = this;returnfunction() {return _function.apply(scope, arguments);  }}
Partes FeiasRicardo Cavalcantikvalcanti@gmail.com
Variáveis globaisTodas as coisas são carregadas no mesmo objeto globalvar foo = value;window.foo = value;foo=value;
EscopoApesar da sintaxe de CBlocos não criam escopoO escopo é sempre da função
Inserção de ;Há um mecanismo de completar com ; alguns comandosreturn ;{ status: true};return{ status: true};=return { status: true};
Palavras reservadasabstract booleanbreak byte case catch charclassconst continue debugger default delete do doubleelseenumexportextendsfalse final finallyfloat for functiongotoifimplementsimport in instanceofint interface longnativenewnull package privateprotectedpublicreturn short static super switch synchronizedthisthrowthrowstransienttruetrytypeof var volatilevoidwhilewithvar method;                // okvar class;                 // illegalobject = {box: value};     // okobject = {case: value};    // illegalobject = {'case': value};  // okobject.box = value;        // okobject.case = value;       // illegalobject['case'] = value;    // ok
Unicodechar em Javascript tem 16bitsUm charunicode são 2 caracteres em javascript
typeoftypeof 98.6  >> ‘number’typeofnull >> ‘object’  my_value === null  //melhorif (my_value && typeofmy_value === 'object') {      // my_value is an object or an array! }typeof /a/  >> ‘object’ ou ‘function’ depende da implementação
parseIntConverte um string num integerPara quando vê um não-dígitoparseInt("16") >> 16parseInt("16 mil") >> 16Se o string começar com 0 é utilizada a base 8parseInt("08")  >> 0parseInt("09")  >> 0Parse int pode receber a baseparseInt("08", 10) >> 8
Ponto fllutuanteJavascript usa IEEE Standard for Binary Floating-Point Arithmetic (IEEE 754)Portanto0.1 + 0.2 !== 0.3Atenção quando utilizar valores monetáriosMelhor multiplicar por 100
NaNSe algum operando for NaN, o resultado da operação será NaNConverter um string em inteiro gera NaNPorémNaN === NaN // falseUse a função isNaNisNaN(NaN) // true
null e undefinedvalue = myObject[name]; if (value == null) {    alert(name + ' not found.'); }Um erroanula o outro!value é undefined, mas o operador == faz o type coersionCuidado: NaN e undefined sãovariáveisglobais!
Partes ruins
=='' == '0'          // false0 == ''            // true0 == '0'           // truefalse == 'false'   // falsefalse == '0'       // truefalse == undefined // falsefalse == null      // falsenull == undefined  // true' \t\r\n ' == 0    // true
withPara acessar os atributos de um objetoProblemas: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;}
evalEvite!Bem como outras formas que recebem código como stringContrutor de FuctionsetTimeoutsetIntervalProblema de segurançaDifícil de checar e de ler
switch FallThroughSwitch-case sem breakFonte de muitos erros, cuidado!
Comandos sem blocoSempre use blocos nos comandosif (ok)    t = true;if (ok)    t = true;    advance(  );viraif (ok) {    t = true;    advance(  );}pareceif (ok) {    t = true;}advance(  );Mas naverdade é
Operadores de bitsOs mesmos de java&    and|    or^    xor~   not>>   signed right shift>>>  unsigned right shift<<   left shiftConvertem para integer e desconvertemLonge do hardware, lentos
TypedWrappersDesnecessáriosnewBoolean(false)Evite o uso de newBoolean, newNumber, new StringTambém evite newObject e newArrayUse {} e []
Para evitar erros

Javascript avançado

  • 1.
  • 2.
    Algumas Ferramentas“Firebug integrateswith 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
  • 3.
    Prototype: introduçãoNão éa biblioteca prototype.jsJavascript usa protótipos no seu modelo de objetosO que importa é o que o objeto faz, e não de quem ele herdaUma função construtora seta seu prototype no objetos que cria
  • 4.
    Prototype: a propriedadeprototypeTodo objeto tem uma propriedade prototypeAo tenta acessar uma propriedade inexistente, javascript busca a propriedade no prototype do objetoE no prototype do prototype...
  • 5.
    Prototype: aumentando prototypesAoincluir propriedades e funções ao prototype de um construtor, elas são incluidas nos objetos que o construtor produzvar cat = newCat("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'mBarsik. Sshhhhhhh!";
  • 6.
    Prototype: mudando oprototypeMudanças no prototype afetam todas as instânciasvar cat = newCat("Barsik");var cat2 = newCat("Murzik");Cat.prototype.animal = "cat";cat.animal >> "cat"cat2.animal >> "cat“Cat.prototype.animal = "dog";cat.animal >> "dog"cat2.animal >> "dog"
  • 7.
    Prototype: propriedadesO objetopode ter suas próprias propriedadesA delegação cuida da prioridadefunctionGadget(/*String*/ name) {this.name = name;}var iphone = newGadget("iPhone");Gadget.prototype.name = "none";iphone.name >> "iPhone"delete iphone.name;iphone.name >> "none"
  • 8.
    Prototype: estendendo JSObjectsPodemos estender inclusive os JS ObjectsString.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, ''); };“ bla “.trim() >> “bla”
  • 9.
  • 10.
    Herança clássicaObjetos sãoinstancias de classesClasses herdam de outra classe
  • 11.
    Herança prototípicaNão háclassesObjetos herdam de objetosUm objeto tem um link para outro objetoNo Firefox é __proto__var newObject = Object(oldObcet)newObjectoldObject__proto__
  • 12.
    Herança prototípicavar oldObject= {firstMethod: function(){...},secondMethod: function(){...},};var newObject = Object(oldObject);newObject.thirdMethod = function(){...};var anotherObject = Object(newObject);anotherObject.thirdMethod();
  • 13.
    Herança prototípicaAo acessaruma propriedade, o interpretador vai primeiro no objeto, depois busca no protótipo do objeto,...depois no protótipo do protótipo...Até Object.prototypenewObjectoldObjectfoo2foo1
  • 14.
    Herança prototípicaMudanças nooldObject serão visíveis no newObject, como já vimosMudanças no newObject não alteram o oldObjectnewObjectoldObjectfoo2foo1
  • 15.
    Herança pseudoclássicaCom herançaprototípica pura, a linguagem deve ter um operador como a função ObjectPara criar novos objetos utilizando um já existenteJavascript usa operadores aparentemente clássicosMas que funcionam prototipicamente
  • 16.
    PseudoclássicaTrês mecanismos:Funções ContruturasOoperador newO atributo prototype, nas funções
  • 17.
    Operador newfunctionContructor(){this.member =...;}Contructor.prototype.firstMethod = function(a,b) {...}Contructor.prototype.secondMethod = function(a,b) {...}var newObject = newConstructor();
  • 18.
    Operador newnewConstructor() retornoum novo objeto ligado ao Constructor.prototypenewObjectoldObjectnewObjectConstructor.prototype
  • 19.
    Operador newA funçãoContructor() pasa o novo objeto na variável thisPara inicizar o novo objetonewObjectConstructor.prototype
  • 20.
    prototypeCada objeto functioncriado tem um atributo prototypeO prototype tem um atributo constructor, que refencia o objeto functionOutros 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
  • 21.
    Herança PseudoclássicaÉ possívelsimular herança clássica atribuindo um objeto criado por um constutor como o protótipo de outraMas não é exatamente herança clássicafunction BiggerConstructor(){};BiggerConstructor.prototype = new MyContructor()
  • 22.
    functionSuperClasse(){}SuperClasse.prototype.hello = function(){alert('superhello')};functionSubClasse(){};SubClasse.prototype = newSuperClasse();SubClasse.prototype.subhello = function(){alert('sub hello')};var o = newSubClasse();o.hello();o.subhello();
  • 23.
    functionSuperClasse(){}SuperClasse.prototype.name= 'super';SuperClasse.prototype.hello= function(){alert(this.name)};functionSubClasse(){this.name= 'sub';};SubClasse.prototype = newSuperClasse();SubClasse.prototype.subhello = function(){alert(this.name)};var o = newSubClasse();o.hello();o.subhello();
  • 24.
  • 25.
    Escopo nas funçõesOescopo é definido pelas funções, e não pelos blocosFunções internas têm acesso às variáveis das funções externasExceto 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?
  • 26.
    ClosuresQuando a funçãointerna dura mais que a externa, o escopo externo é preservadoIsso se chama closure
  • 27.
    Um closure simplesvarf = function(x){ var m = function(y){returnx * y; }return m;}var dobro = f(2);var triplo = f(3);alert(dobro(10));alert(triplo(10));Quando f() é executado, um novo m() é criadoEnquanto m() existir, seu escopo existe, e o do seu ‘pai’ também
  • 28.
  • 29.
    Clojures: Dados privadosvar quo = function (status) {return {get_status: function ( ) {return status; } };};var myQuo = quo("amazed");alert(myQuo.get_status( ));
  • 30.
    Closures: timersvar 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);
  • 31.
    Closure: eventhandlerFunção queadiciona um eventhandler 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?
  • 32.
    Closure: eventhandlerExemplo corretovaradd_the_handlers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) {nodes[i].onclick = function (i) {returnfunction (e) {alert(i); };} (i); }};
  • 33.
  • 34.
    CurryFunçõ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};
  • 35.
    Função curryCurry cria um closure queguarda a função original e seusargumentospararealizar o curryingQuandoexecutada, elaretorna o resultadodafunção original com osargumentospassadosao curry e ospassados a elavar mult = function (a, b) {return a * b};var duplicar = mult.curry(2);varseis = duplicar(3); //mult.curry(2)(3) >>> 6
  • 36.
    Function.prototype.curry = function( ) {varargs = arguments, that = this; return function ( ) { return that.apply(null, args.concat(arguments)); };}); //PROBLEMA: arguments não é um array
  • 37.
    Função curry: finalFunction.prototype.curry= function( ) { var slice = Array.prototype.slice,args = slice.apply(arguments),that = this;returnfunction ( ) {returnthat.apply(null, args.concat(slice.apply(arguments))); };});
  • 38.
    Closures: callbacksvar replace= function (el, url){ var callback = function(t){el.innerHTML = t; };makeXHR(callback, url); // ajax}replace (myEl, minhaURL);
  • 39.
    Closures: cuidadosEvite criarfunções em loopsPara evitar closures indesejadosAtenção com o thisMais sobre isso com bind
  • 40.
  • 41.
    Thiswindow.name= "thewindowobject"functionscopeTest() {returnthis.name}scopeTest()//-> "thewindowobject"var foo = {name: "thefooobject!",otherScopeTest: function() { returnthis.name }}foo.otherScopeTest()// -> "thefooobject!"
  • 42.
    Javascript é dinâmica//atribuindoa função, SEM executá-lawindow.test= foo.otherScopeTest//chamando a funçãotest() ; // -> "the window object"
  • 43.
    FunctionbindEu gostaria deescolher o ‘this’ da minha funçãowindow.test = foo.otherScopeTest.bind(foo);test() // -> "thefooobject!"Function.prototype.bind = function(scope) { var _function = this;returnfunction() {return _function.apply(scope, arguments); }}
  • 44.
  • 45.
    Variáveis globaisTodas ascoisas são carregadas no mesmo objeto globalvar foo = value;window.foo = value;foo=value;
  • 46.
    EscopoApesar da sintaxede CBlocos não criam escopoO escopo é sempre da função
  • 47.
    Inserção de ;Háum mecanismo de completar com ; alguns comandosreturn ;{ status: true};return{ status: true};=return { status: true};
  • 48.
    Palavras reservadasabstract booleanbreakbyte case catch charclassconst continue debugger default delete do doubleelseenumexportextendsfalse final finallyfloat for functiongotoifimplementsimport in instanceofint interface longnativenewnull package privateprotectedpublicreturn short static super switch synchronizedthisthrowthrowstransienttruetrytypeof var volatilevoidwhilewithvar method; // okvar class; // illegalobject = {box: value}; // okobject = {case: value}; // illegalobject = {'case': value}; // okobject.box = value; // okobject.case = value; // illegalobject['case'] = value; // ok
  • 49.
    Unicodechar em Javascripttem 16bitsUm charunicode são 2 caracteres em javascript
  • 50.
    typeoftypeof 98.6 >> ‘number’typeofnull >> ‘object’ my_value === null //melhorif (my_value && typeofmy_value === 'object') { // my_value is an object or an array! }typeof /a/ >> ‘object’ ou ‘function’ depende da implementação
  • 51.
    parseIntConverte um stringnum integerPara quando vê um não-dígitoparseInt("16") >> 16parseInt("16 mil") >> 16Se o string começar com 0 é utilizada a base 8parseInt("08") >> 0parseInt("09") >> 0Parse int pode receber a baseparseInt("08", 10) >> 8
  • 52.
    Ponto fllutuanteJavascript usaIEEE Standard for Binary Floating-Point Arithmetic (IEEE 754)Portanto0.1 + 0.2 !== 0.3Atenção quando utilizar valores monetáriosMelhor multiplicar por 100
  • 53.
    NaNSe algum operandofor NaN, o resultado da operação será NaNConverter um string em inteiro gera NaNPorémNaN === NaN // falseUse a função isNaNisNaN(NaN) // true
  • 54.
    null e undefinedvalue= myObject[name]; if (value == null) { alert(name + ' not found.'); }Um erroanula o outro!value é undefined, mas o operador == faz o type coersionCuidado: NaN e undefined sãovariáveisglobais!
  • 55.
  • 56.
    =='' == '0' // false0 == '' // true0 == '0' // truefalse == 'false' // falsefalse == '0' // truefalse == undefined // falsefalse == null // falsenull == undefined // true' \t\r\n ' == 0 // true
  • 57.
    withPara acessar osatributos de um objetoProblemas: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;}
  • 58.
    evalEvite!Bem como outrasformas que recebem código como stringContrutor de FuctionsetTimeoutsetIntervalProblema de segurançaDifícil de checar e de ler
  • 59.
    switch FallThroughSwitch-case sembreakFonte de muitos erros, cuidado!
  • 60.
    Comandos sem blocoSempreuse blocos nos comandosif (ok) t = true;if (ok) t = true; advance( );viraif (ok) { t = true; advance( );}pareceif (ok) { t = true;}advance( );Mas naverdade é
  • 61.
    Operadores de bitsOsmesmos de java& and| or^ xor~ not>> signed right shift>>> unsigned right shift<< left shiftConvertem para integer e desconvertemLonge do hardware, lentos
  • 62.
    TypedWrappersDesnecessáriosnewBoolean(false)Evite o usode newBoolean, newNumber, new StringTambém evite newObject e newArrayUse {} e []
  • 63.