Perguntas e respostas sobre JavaScript

Recentemente, o SmartSpate decidiu coletar perguntas sobre JavaScript e respondê-las. O material, cuja tradução publicamos, contém um pouco mais de duas dúzias de perguntas sobre JavaScript e as respostas para elas. A gama de tópicos abordados aqui é bastante ampla. Em particular, esses são recursos da linguagem, problemas encontrados pelos programadores ao escrever o código JS, funcionam no navegador e no Node.js.



Pergunta número 1. Herança do protótipo


Acostumei-me às aulas "clássicas", mas decidi aprender JavaScript. Tenho um problema ao entender o modelo do protótipo. Se possível, explique, na forma de modelos, a capacidade de criar "classes" em JavaScript, conte-nos sobre métodos e propriedades particulares e abertos de classes. Eu entendo que muito já foi escrito sobre isso e que, em JavaScript, os métodos e propriedades dos objetos estão, por padrão, disponíveis ao público, mas eu gostaria de entender tudo isso corretamente. Como a herança de protótipo funciona em JavaScript?

▍ Resposta


A herança clássica é muito semelhante à maneira como as pessoas herdam os genes de seus ancestrais. As pessoas têm algumas habilidades básicas comuns, como caminhar e conversar. Além disso, cada pessoa tem algumas peculiaridades. As pessoas não podem mudar o que pode ser chamado de "classe", mas podem mudar suas próprias "propriedades" dentro de certos limites. Ao mesmo tempo, avós, mães e pais não podem influenciar os genes de filhos ou netos no processo de suas vidas. Então, tudo está organizado na Terra, mas vamos imaginar outro planeta no qual os mecanismos de herança trabalhem de uma maneira especial. Digamos que alguns organismos capazes de mutações usem os mecanismos de "herança telepática" lá. Isso se expressa no fato de que eles podem alterar as informações genéticas de seus próprios descendentes no processo de sua vida.

Considere o exemplo da herança neste planeta estranho. O objeto Pai herda genes do objeto Avô, e o objeto Filho herda informações genéticas do Pai. Cada habitante deste planeta pode sofrer mutações e alterar livremente os genes de seus descendentes. Por exemplo, em "Avô", a pele tem uma cor verde. Este sinal é herdado pelo "Pai" e "Filho". De repente, "Avô" decide que ele está cansado de ser verde. Agora ele quer ser azul e mudar sua cor de pele (em termos de JS - altera o protótipo de sua classe), passando "telepaticamente" essa mutação para o "Pai" e o "Filho". Depois disso, o “Pai”, acreditando que o “Avô” havia sobrevivido da mente, decide mudar seus genes para que fique verde novamente (ou seja, ele muda seu próprio protótipo). Essas mudanças são "telepaticamente" transmitidas ao "Filho". Como resultado, o "Pai" e o "Filho" têm a pele verde novamente. Ao mesmo tempo, "Avô" ainda é azul. Agora, não importa o que ele faça com sua cor, isso não afetará mais ninguém. E tudo isso se deve ao fato de o "Pai" definir explicitamente a cor de sua pele em seu "protótipo", e o "Filho" herdar essa cor. Então o "Filho" pensa assim: "Eu ficarei preto. E que meus descendentes herdem cores de meu pai. Para fazer isso, ele muda sua própria propriedade (e não a propriedade de seu protótipo) de forma que sua propriedade afete sua cor, mas não seus descendentes. Expressamos tudo isso na forma de código:

var Grandfather = function () {}; //  Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; //  Father Father.prototype = new Grandfather (); //  - ,        var Son = function () {}; //  Son Son.prototype = new Father (); // Son   Father var u = new Grandfather (); //   Grandfather var f = new Father (); //   Father var s = new Son (); //   Son //     console.log ([u.color, f.color, s.color]); // ["green", "green", "green"] //  Grandfather        Grandfather.prototype.color = 'blue'; console.log ([u.color, f.color, s.color]); // ["blue", "blue", "blue"] //  Father      -   ,     Father.prototype.color = 'green'; //      : // Grandfather.prototype.color = 'green'; console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"] // ,        Grandfather     color,      Grandfather.prototype.color = 'blue'; console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"] //  Son,  ,       Grandfather,    s.color = 'black'; //        console.log ([u.color, f.color, s.color]); // ["blue", "green", "black"] var SonsSon = function () {}; //  SonsSon -   Son SonsSon.prototype = new Son (); //  var ss = new SonsSon (); //   SonsSon //         console.log ([u.color, f.color, s.color, ss.color]); // ["blue", "green", "black", "green"] 

Pergunta número 2. Criar objetos


Se você criar novas instâncias de objetos usando a new palavra-chave, como se proteger contra erros? É assim que eu costumo trabalhar:

  1. Eu sempre construo funções construtoras para que elas comecem com uma letra maiúscula.
  2. Verifico a exatidão da operação usando o construtor this instanceof Function_Name (tento não usar o construto do tipo this instanceof arguments.callee por motivos de desempenho).
  3. Essa abordagem é semelhante à anterior, mas a comparação é feita com window , porque não gosto de codificar os nomes das entidades e não preciso escrever código para ambientes que não sejam o navegador.

Qual é o modelo mais conveniente para criar objetos?

▍ Resposta


É melhor, ideologicamente e com base na familiaridade desse método, criar objetos usando a new palavra-chave. Nesse caso, as funções do construtor devem receber nomes começando com uma letra maiúscula.

Eu prefiro seguir as regras e não executar verificações adicionais nos construtores. Se o construtor é chamado sem new e o trabalho começa no escopo global, isso pode ser comparado com "auto-engano". Ao mesmo tempo, não recomendo que você lide com situações em designers nos quais elas são chamadas sem a new palavra-chave. Por exemplo, pode ser assim: se o construtor for chamado sem new , então, de qualquer maneira, um novo objeto será criado e retornado. Essa abordagem é ideologicamente incorreta e leva a erros.
Aqui está um exemplo de trabalho com um construtor.

 var Obj = function () {   "use strict";   this.pew = 100; }; //  let o = new Obj(); o.pew++; console.log(o.pew); //101 // .   Obj (); // TypeError: this is undefined 

É melhor não usar a new palavra-chave para métodos de fábrica e nos casos em que não há necessidade de um construtor, quando será mais conveniente criar um objeto usando um literal de objeto. Digamos que o código do construtor mostrado no exemplo a seguir seja explicitamente redundante:

 //    . var Obj = function () {    if (! (this instanceof Obj)) {        return new Obj ();    }    this.pew = 100; }; 

Se, mesmo para criar um objeto pequeno, você ainda precisar de um construtor, é melhor fazer isso:

 var Obj = function () {    "use strict";    this.pew = 100; }; 

Aqui, como mostrado acima, devido ao fato de o construtor funcionar no modo estrito, ocorrerá um erro ao chamá-lo sem new .

Pergunta número 3. Intercepção de cliques do mouse


Como, usando JavaScript, para saber em qual botão do mouse é clicado?

▍ Resposta


Clicar nos botões do mouse gera eventos de mousedown mouse e mouse. Nesse caso, o evento click é gerado apenas pelo botão esquerdo do mouse. No manipulador de eventos, é necessário verificar o código localizado na propriedade event.button para descobrir qual botão está pressionado (0 - esquerda, 1 - meio, 2 - direita). No entanto, no IE, tudo parece um pouco diferente. Considere um exemplo:

 var button = document.getElementById ('button'),              // 0 1 2    buttonMap = ['Left', 'Middle', 'Right'],    handler = function (event) {        event = event || window.event;        alert (buttonMap [event.button] + 'id:' + event.button);    }; if (button.addEventListener) {     button.addEventListener ('mousedown', handler, false); } else {     // IE 0 1 2 3 4     buttonMap = ['???', 'Left', 'Right', '???', 'Middle'];     button.attachEvent ('onmousedown', handler); } 

A biblioteca jQuery leva esse recurso do IE em consideração; portanto, ao usá-lo em qualquer navegador, basta verificar o valor da propriedade event.which em vez de mexer no event.button :

 $('button').mousedown(function (event) {   alert(['Left', 'Middle', 'Right'][event.which]); }); 

Pergunta número 4. Intercepção de pressionamentos de teclas nas teclas do teclado


É possível interceptar, usando JavaScript, pressionando as teclas de seta (em particular, pressionando as teclas Para baixo e Para cima), para que, depois de clicar nelas, o navegador não role a página? Se isso for possível, quais são os recursos para implementar isso em diferentes navegadores? Suponha que uma página seja exibida em uma página que não cabe inteiramente na tela. A movimentação pelas células desta tabela deve ser organizada usando as teclas de seta, e é necessário que o navegador não role a página quando você clicar nessas teclas.

▍ Resposta


Para implementar algo parecido com isto, primeiro você precisa desativar a resposta padrão do sistema para controlar ações. Por exemplo, as teclas de seta e a roda do mouse rolam a página; clicar com o botão direito do mouse na página exibe um menu de contexto; quando você clica no botão submit , a função form.submit() é form.submit() ; quando você clica no campo de entrada, ele recebe o foco de entrada; quando você clica no link, o navegador carrega a página para a qual ela leva.

Isso pode ser feito de maneiras diferentes . Por exemplo, assim:

 window.addEventListener("keydown", function(e) {   //  -   if([37, 38, 39, 40].indexOf(e.keyCode) > -1) {       e.preventDefault();   } }, false); 

A página seguinte normalmente não responde aos pressionamentos de tecla de seta.
Uma coisa importante a ser observada aqui. O preventDefault() antes que a ação padrão seja executada. Por exemplo, se você clicar em um campo para impedir que ele ganhe foco de entrada, será necessário travar o manipulador apropriado em um evento que esteja na cadeia de eventos antes da ação padrão. No nosso caso, este é um evento de mousedown :

 $('input').bind ('mousedown', function (event) {   event.preventDefault();   //    return false; }); 

Quando você clica no campo de entrada, ocorrem os seguintes eventos - na sequência em que são mostrados aqui:

  1. mousedown
  2. focus (antes disso, outro objeto que está perdendo o foco acionará um evento de blur )
  3. mouseup
  4. click

Se tentarmos impedir que o elemento obtenha foco de entrada, o uso de manipuladores de eventos para isso, começando com o manipulador de eventos focus , não nos ajudará.

Pergunta número 5. Parar animação GIF e tecla ESC


Como lidar com o problema de interromper a animação GIF ao pressionar a tecla ESC?

▍ Resposta


Aqui você pode usar a mesma abordagem que consideramos acima. Em alguns navegadores, pressionar a tecla ESC interrompe a animação GIF e o carregamento da página. Esse é o comportamento padrão deles e, para impedir que eles se comportem dessa maneira, o preventDefault() evento preventDefault() é útil para nós, como antes. O código da tecla ESC é 27.

Pergunta número 6. Parênteses em IIFE


Como a construção de dois parênteses é usada ao declarar uma Expressão de Função Invocada Imediatamente (IIFE)?

▍ Resposta


Os colchetes nessa situação permitem que o analisador entenda que existe uma função na frente deles que precisa ser executada. Mas ele também precisa entender o que são esses colchetes - o operador de agrupamento ou uma construção indicando a necessidade de chamar a função. Por exemplo, se usarmos dois colchetes, como mostrado abaixo, SyntaxError um erro SyntaxError :

 function () { //  }() 

Isso se deve ao fato de a função não ter um nome (você deve especificar seus nomes nas declarações da função).

Vamos tentar reescrever esse código, dando um nome à função:

 function foo() { //  }() 

Agora que a função tem um nome, essa construção, teoricamente, deve parecer bastante normal do ponto de vista do sistema. Mas o erro não desaparece, embora agora tenha a ver com o operador de agrupamento, dentro do qual não há expressão. Observe que, nesse caso, a instrução de agrupamento é seguida pelo operador de agrupamento, e não uma sequência de colchetes que informa ao sistema que a função anterior a ela deve ser chamada.

Geralmente o IIFE é projetado da seguinte maneira:

 (function () {   //  })() 

Mas existem outras maneiras, cuja essência é de alguma forma indicar ao analisador que antes era apenas uma expressão funcional que precisa ser executada:

 !function () { //  }(); +function () { //  }(); [function() { //  }()]; var a = function () { //  }(); 

IIFE são amplamente utilizados na programação JavaScript. Por exemplo, essa construção é usada no jQuery. Com sua ajuda, você pode criar fechamentos. De fato, estamos falando sobre o fato de que, usando o IIFE, o programador pode executar algum código no escopo local. Isso ajuda a proteger o escopo global da poluição e permite otimizar o acesso a variáveis ​​globais. Tais projetos são bem minificados.

Pergunta número 7. Passando código em resposta a solicitações


O servidor, no processo de interação do AJAX com o cliente, no corpo da resposta, envia ao cliente uma sequência de alert ('Boom !!!'); . O cliente aceita a resposta e executa esse código usando a função eval() . Como se chama? Afinal, o que está contido na resposta do servidor não é JSON, XML ou HTML. O que você pode dizer sobre a execução no cliente do código que vem do servidor na forma do corpo da resposta a uma determinada solicitação?

▍ Resposta


De fato, não existe um nome especial para esse esquema de interação cliente-servidor. E este é um esquema de interação do sistema que é fortemente desencorajado. Isso é tão ruim quanto armazenar o código PHP em um banco de dados e depois executá-lo usando métodos de linguagem apropriados. Mesmo se não levarmos em consideração considerações ideológicas, podemos dizer que essa arquitetura é extremamente inflexível; portanto, se o projeto em que é usada, será necessário, à medida que se desenvolve, mudar alguma coisa, isso não será fácil. Aqui vemos um exemplo de arquitetura de sistema ruim quando dados são misturados com elementos de código e interface. Para alterar algo nesse sistema, primeiro você precisa entender os meandros de sua arquitetura complexa e, depois de fazer as alterações, "confunde" tudo novamente. Não estou falando sobre reutilização de código.

Para simplificar o suporte ao código, você precisa buscar a maior separação possível de partes do sistema e reduzir o número de interdependências dessas partes. Para garantir uma conectividade ruim de partes do sistema, ou seja, para garantir que um fragmento do aplicativo possa ser extraído dele ou, com a menor complexidade, substituído por outro, você pode usar mecanismos de eventos ou soluções arquiteturais especiais, como MVC.

Pergunta número 8. Executando operações pesadas no encadeamento principal


Como organizar a execução de certos comandos que exigem muitos recursos em JavaScript e não "suspender" o script inteiro?

▍ Resposta


JavaScript é uma linguagem de thread único. O código das páginas da Web é executado no mesmo encadeamento e as transformações da árvore DOM são executadas. Existem também temporizadores. Cada vez que você executa algumas operações que consomem recursos (ciclos, chamadas para funções "pesadas"), isso leva a uma desaceleração na interface do usuário ou mesmo ao seu bloqueio completo. Se as operações executadas não tiverem uma carga particularmente grande no sistema, o impacto na interface será tão insignificante que os usuários simplesmente não perceberão. Para tornar a computação pesada fora do segmento principal, o conceito de trabalhadores da Web foi introduzido em JavaScript.

Se o uso de trabalhadores não for possível, você precisará otimizar os ciclos e as funções "pesadas". No livro "JavaScript. Otimização de desempenho ”Nicholas Zakas diz que o usuário não notará nada se o fluxo da interface do usuário estiver bloqueado por 100 ms ou menos.

A partir dessa idéia, podemos concluir que os cálculos com uso intensivo de recursos podem ser divididos em fragmentos, cuja implementação leva no máximo 100 ms, após o qual o encadeamento principal deve ser liberado.

Aqui está um código de exemplo do livro acima:

 function timedProcessArray(items, process, callback) {   var todo = items.concat();   //    setTimeout(function () {       var start = +new Date();       do {           process(todo.shift());       } while (todo.length > 0 && (+new Date() - start < 50));       if (todo.length > 0){           setTimeout(arguments.callee, 25);       } else {           callback(items);       }   }, 25); } function saveDocument(id) {   var tasks = [openDocument, writeText, closeDocument, updateUI];   timedProcessArray(tasks, [id], function(){       alert("Save completed!");   }); } 

A função timedProcessArray() bloqueia o encadeamento principal por 25 ms, executa uma sequência de ações e o libera por 25 ms, após o que esse processo é repetido.

Pergunta número 9. Sobre o redimensionamento da janela do navegador


Posso descobrir de alguma forma que o usuário terminou de redimensionar a janela do navegador?

▍ Resposta


Não há evento especial que permita que você descubra. Mas você pode descobrir se o usuário está redimensionando a janela usando o evento onresize . Este método, no entanto, não é muito preciso.

Aqui está um rascunho de código para resolver esse problema.

 var time = 0,   timerId,   TIME_ADMISSION = 100; // 0.1  function onresizeend () {   console.log('onresizeend'); }; function resizeWatcher () {   if (+new Date - time >= TIME_ADMISSION) {       onresizeend();       if (timerId) {           window.clearInterval(timerId);           timerId = null;       }   } }; $(window).resize(function () {   if (!timerId) {       timerId = window.setInterval(resizeWatcher, 25);   }   time = +new Date; }); 

Pergunta número 10. Abrindo novas janelas e guias do navegador


Como, usando o método window.open() , para abrir uma nova janela do navegador e não uma nova guia?

▍ Resposta


O comportamento exato do método window.open() depende do navegador. O Opera sempre abre novas abas (embora pareçam janelas), o Safari sempre abre janelas (embora esse comportamento possa ser alterado). O comportamento do Chrome, Firefox e Internet Explorer pode ser controlado.

Portanto, se um parâmetro adicional (posição da janela window.open() passado para o método window.open() , uma nova janela será aberta:

 window.open('http://www.google.com', '_blank', 'toolbar=0,location=0,menubar=0'); 

Se apenas um link for passado para esse método, uma nova guia do navegador será aberta:

 window.open('http://www.google.com'); 

Muitas vezes, você precisa abrir uma nova guia do navegador. Pode haver problemas com isso no navegador Safari. Por padrão (depende das configurações), o navegador, quando window.open() é chamado, abre uma nova janela. Mas se você clicar no link, enquanto pressiona as teclas Ctrl + Shift/Meta + Shift , uma nova guia será aberta (independentemente das configurações). No exemplo a seguir, simularemos o evento de click gerado quando as Ctrl + Shift/Meta + Shift são pressionadas:

 function safariOpenWindowInNewTab (href) {    var event = document.createEvent ('MouseEvents'),        mac = (navigator.userAgent.indexOf ('Macintosh')> = 0); //  Ctrl + Shift + LeftClick / Meta + Shift + LeftClick ()    //       event.initMouseEvent (        / * type * / "click",        / * canBubble * / true        / * cancelable * / true,        / * view * / window,        / * detail * / 0,        / * screenX, screenY, clientX, clientY * / 0, 0, 0, 0,        / * ctrlKey * /! mac,        / * altKey * / false,        / * shiftKey * / true        / * metaKey * / mac,        / * button * / 0,        / * relatedTarget * / null    ); //     ,   ,         $ ('<a/>', {'href': href, 'target': '_blank'}) [0] .dispatchEvent (event); } 

Pergunta nº 11. Objetos de cópia profunda


Como organizar efetivamente a cópia profunda de objetos?

▍ Resposta


Se o objeto cuja cópia você deseja criar (vamos chamá-lo de oldObject ) não for alterado, será mais eficaz fazer isso através de seu protótipo (isso é feito muito rapidamente):

 function object(o) {   function F() {}   F.prototype = o;   return new F(); } var newObject = object(oldObject); 

Se você realmente precisar executar a operação de clonagem de um objeto, o caminho mais rápido será recursivamente, otimizando esse processo, passando por suas propriedades. Talvez este seja o algoritmo mais rápido para criar cópias profundas de objetos:

 var cloner = {   _clone: function _clone(obj) {       if (obj instanceof Array) {           var out = [];           for (var i = 0, len = obj.length; i < len; i++) {               var value = obj[i];               out[i] = (value !== null && typeof value === "object") ? _clone(value) : value;           }       } else {           var out = {};           for (var key in obj) {               if (obj.hasOwnProperty(key)) {                   var value = obj[key];                   out[key] = (value !== null && typeof value === "object") ? _clone(value) : value;               }           }       }       return out;   }, clone: function(it) {       return this._clone({       it: it       }).it;   } }; var newObject = cloner.clone(oldObject); 

Se você usar jQuery, poderá recorrer às seguintes construções:

 //   var newObject = jQuery.extend ({}, oldObject); //   var newObject = jQuery.extend (true, {}, oldObject); 

Pergunta número 12. Destruidores de JavaScript


Como criar algo como um destruidor em JavaScript? Como gerenciar o ciclo de vida dos objetos?

▍ Resposta


Em JavaScript, um objeto será excluído da memória após a última referência a ele desaparecer:

 var a = {z: 'z'}; var b = a; var c = a; delete az; delete a; //    a console.log (b, c); // ,  ,    

Usar algo como um “destruidor” no JavaScript resulta apenas na limpeza do conteúdo do objeto, mas não na exclusão da memória.

Pergunta número 13. Processamento de dados binários


É possível processar dados binários em JavaScript? E se sim, como?

▍ Resposta


Se você precisar trabalhar com dados binários em um aplicativo JavaScript, tente usar a biblioteca Analisador Binário . Mas o código dela é um inferno. No ES6 +, há uma sugestão sobre o tipo StructType (é o mesmo que o apresentado em C ++ pelo tipo composto para a struct especificada). Esse tipo de dado é necessário para simplificar o trabalho com dados binários. Trabalhar com isso pode ser algo como isto:

 const Point2D = new StructType({ x: uint32, y: uint32 }); const Color = new StructType({ r: uint8, g: uint8, b: uint8 }); const Pixel = new StructType({ point: Point2D, color: Color }); const Triangle = new ArrayType(Pixel, 3); let t = new Triangle([{ point: { x:  0, y: 0 }, color: { r: 255, g: 255, b: 255 } },                     { point: { x: 5, y: 5 }, color: { r: 128, g: 0,   b: 0 } },                     { point: { x: 10, y: 0 }, color: { r: 0,   g: 0, b: 128 } }]); 

Pergunta número 14. Alterando variáveis ​​em uma função de outra função


Como alterar variáveis ​​localizadas em uma função de outra função?

▍ Resposta


Aqui você pode aplicar várias abordagens:

  1. Você pode usar o link para o contexto da função de seu interesse (a função primer() no exemplo a seguir) na função smth() .
  2. Você pode passar uma função criada no contexto da função primer() para a função smth() .

     var primer = function () {    var a, b, c, d, e = {}; smth (function () {        a = 1;        b = 2;        c = 3;        d = 4;    }, e); alert ([a, b, c, d, e.pewpew]); }, smth = function (callback, e) {    callback ();    e.pewpew = "pewpew"; }; primer (); 
  3. Anteriormente (antes do Firefox 3.6), era possível __parent__ o contexto usando a propriedade __parent__ , mas já no Firefox 4 esse recurso foi removido.

Pergunta número 15. Trabalhar com funções


Diga-nos como as funções podem ser chamadas em JavaScript.

▍ Resposta


Suponho que não seja necessário falar sobre como chamar funções, métodos e construtores durante o trabalho normal com eles. Vamos falar sobre como usar os métodos call() e apply() .

Usando call () para configurar o construtor de um objeto


 //   function extend (newObj, oldObj) {   function F () {};   F.prototype = oldObj.prototype;   newObj.prototype = new F ();   return newObj }; var Obj = function () {   this.obj_var = 100; }; Obj.prototype.obj_proto_var = 101; var NewObj = function () {   Obj.call (this); //   Obj     obj_var   this.new_obj_var = 102; }; extend (NewObj, Obj) NewObj.prototype.new_obj_proto_var = 103; new NewObj (); // {new_obj_proto_var: 103, new_obj_var: 102, obj_proto_var: 101, obj_var: 100} 

Converter objetos do tipo matriz em matrizes


Os objetos do tipo matriz são semelhantes aos do JavaScript, mas não são. Em particular, isso é expresso no fato de que esses objetos não possuem métodos de matrizes comuns. Entre esses objetos, por exemplo, podem ser observados os arguments objeto de funções tradicionais e os resultados do método getElementsByTagName () .

 // document.getElementsByTagName ("div")  ,   ,    , ,  ,        document.getElementsByTagName ("div"). forEach (function (elem) {    // ... }); // TypeError: document.getElementsByTagName ("div"). forEach is not a function //    Array.prototype.slice.call(document.getElementsByTagName("div")).forEach (function (elem) {   // OK }); //        console.log(Array.prototype.slice.call ('pewpew')) // ["p", "e", "w", "p", "e", "w"] //  IE8    

Criando Objetos Wrapper


Essa técnica de usar call() e apply() permite criar objetos wrapper. , - foo() , bar() .

:

 function bar () {console.log(arguments)} // foo (context, arg1, arg2, ...) function foo () {    var context = arguments [0];    var args = Array.prototype.slice.call (arguments, 1); //     bar    bar.apply (context, args); } 

Function.call.apply() :

 function foo() {   Function.call.apply(bar, arguments); } 

, Function.call.apply() , , foo() , bar .

№16.


, , ?


. , Firefox 3.6, __parent__ , .

№17.


, , , eval() ?


, . , :

 // 1:  eval() (function () {    "use strict";    var globalObject = (0, eval) ("this"); //  :)    return globalObject; } ()); // 2:    (function (global) {    // ... } (window)); // 3:      (function () {    return this; } ()); // 4:            ,       . //  -    "use strict"; (function (global) {    // global }) (this); 

№18.


, JavaScript, , ?


JavaScript - « ». . . , :

 $('#smth').click(function onSmthClick(event) {   if (smth) {       //         event.handlerFunction = onSmthClick;       event.handlerContext = this;       //         //  otherObjectSetSomeEvent   event.handlerFunction          otherObjectSetSomeEvent(event);   } else {       //  -    } }); 

— , . , 2 :

 $('#smth'). click (function handler1 (event) {   if (smth) {       //         leftObjectSetSomeEvent(event, function handler2 (e) {           //  -   e       });   } else {       //  -    } }); function leftObjectSetSomeEvent(event, callback) {   callback (event);   //    } 

№19.


JavaScript ? — , .


click «» DOM. (, , ).

 // jQuery $(window).bind ('click', function (e) {   console.log ('Clicked on', e.target); }); //       $('#pewpew').delegate ('*', 'click', function(e) {   console.log('Clicked on', e.target); }); //     $('#pewpew').delegate('.pewpew', 'click', function (e) {   console.log ('Clicked on element with .pewpew class name'); }); 

№20. XHR-


XHR- jQuery?


, - :

 function xhr(m, u, c, x) { with(new XMLHttpRequest) onreadystatechange = function (x) {   readyState ^ 4 || c(x.target) }, open(m, u), send() } 

- :

 function xhr(m, u, c, x) { with(new(this.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")) onreadystatechange = function (x) {   readyState ^ 4 || c(x) }, open(m, u), send() } 

:

 xhr('get', '//google.com/favicon.ico', function (xhr) { console.dir(xhr) }); 

№21. -


(reflow) (repaint) -?


  1. requestAnimationFrame() , , setInterval() setTimeout() . , , , , , . , JavaScript- CSS- SVG-. , , , , , , . , , .
  2. float- ( ).
  3. DOM. , , , DOM ( ).
  4. — . ( , , ). Aqui está um exemplo:

     //      element.style.left = "150px;"; // ... element.style.color = "green"; //  ,   ,    element.setAttribute ('style', 'color: green; left: 150px'); 
  5. ( ).
  6. — ( style.display = "none" ). , .

, -, . , , , , .

  1. .
  2. DOM- ( — ).
  3. Document.querySelectorAll() firstElementChild .
  4. , document.getElementsByTagName() ( , DOM, ).

№22. Node.js


Node.js, , ?


, ( PHP Apache). , , . Node.js — . , , cluster . (master) - (worker). , .

№23. runInNewContext() Node.js


runInNewContext() Node.js.


. , ( Node.js- Nodester). - , runInNewContext() . , «», . «» , , runInNewContext() .

Sumário


JavaScript . , - , .

Caros leitores! , - , , JavaScript , ?

Source: https://habr.com/ru/post/pt436454/


All Articles