Curso básico de Javascript – (parte 2)

24. Qual é o valor do this JavaScript?

Basicamente, thisrefere-se ao valor do objeto que está atualmente executando ou chamando a função. Eu digo atualmente devido à razão pela qual o valor disso muda dependendo do contexto em que o usamos e de onde o usamos.

const carDetails = {
     name: "Camaro",
     yearBought: 2005,
     getName(){
        return this.name;
     },
     isRegistered: true
   };

   console.log(carDetails.getName()); // logs Camaro

É o que normalmente esperávamos, porque no método getName retornamos this.name, thisnesse contexto se refere ao carDetails objeto que atualmente é "proprietário" da função em execução.

Ok, vamos adicionar alguns códigos para torná-los estranhos. Abaixo da instrução console.log, adicione estas três linhas de código

A segunda console.logafirmação imprime a palavra Toyota Corolla, que é estranha, porque em nossa primeira console.logafirmação ela imprimiu Toyota Corolla. A razão para isso é que o método getCarName possui um objeto "proprietário" diferente que é o objeto window. Declarar variáveis com a var no escopo global anexa propriedades no objeto window com o mesmo nome que as variáveis. Lembre-se, this no escopo global, refere-se ao objeto window quando use strict não é usado.

console.log(getCarName === window.getCarName); //logs true
console.log(getCarName === this.getCarName); // logs true

this e window neste exemplo, consulte o mesmo objeto.

Uma maneira de resolver esse problema é usar os métodos apply e call nas funções.

console.log(getCarName.apply(carDetails)); //logs Camaro
console.log(getCarName.call(carDetails));  //logs Camaro

Os métodos apply e call esperam que o primeiro parâmetro seja um objeto que seria valor this dentro dessa função.

Expressão de função IIFE ou invocada imediatamente, funções declaradas no escopo global, funções anônimas e funções internas em métodos dentro de um objeto têm um padrão disso que aponta para o objeto de janela.

(function (){
     console.log(this);
   })(); //logs the "window" object

   function iHateThis(){
      console.log(this);
   }

   iHateThis(); //logs the "window" object  

   const myFavoriteObj = {
     guessThis(){
        function getName(){
          console.log(this.name);
        }
        getName();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

   myFavoriteObj.guessThis(); //logs the "window" object
   myFavoriteObj.thisIsAnnoying(function (){
     console.log(this); //logs the "window" object
   });

Se queremos obter o valor da propriedade name que é LinuxUpdate no objeto myFavoriteObj, existem duas maneiras de resolver isso.

Primeiro, salvamos o valor de thisem uma variável.

const myFavoriteObj = {
     guessThis(){
         const self = this; //saves the this value to the "self" variable
         function getName(){
           console.log(self.name);
         }
         getName();
     },
     name: 'LinuxUpdate',
     thisIsAnnoying(callback){
       callback();
     }
   };

Neste exemplo imagem, salvamos o valor de this qual seria o objeto myFavoriteObj. Para que possamos acessá-lo dentro da função getName interna.

Segundo, usamos as funções de seta ES6.

const myFavoriteObj = {
     guessThis(){
         const getName = () => { 
           //copies the value of "this" outside of this arrow function
           console.log(this.name);
         }
         getName();
     },
     name: 'LinuxUpdate',
     thisIsAnnoying(callback){
       callback();
     }
   };

O Arrow Functions não possui seu próprio this. Ele copia o valor do escopo this lexical anexo ou, neste exemplo, o valor do this com função interna getName que seria o objeto myFavoriteObj. Também pode determinar o valor sobre this que uma função que é invocada.

25. Qual é o prototype de um objeto?

O prototype em termos mais simples é um objeto e é usado como um substituto para propriedades e métodos, se existir no objeto atual. É a maneira de compartilhar propriedades e funcionalidades entre objetos. É o conceito central da herança prototípica do JavaScript .

const o = {};
console.log(o.toString()); // logs [object Object] 

Mesmo que o método o.toString não exista no objeto o, ele não gera um erro, mas retorna uma string [object Object]. Quando uma propriedade não existe no objeto, ela analisa seu protótipo e, se ainda não existe, analisa o protótipo do protótipo e assim por diante até encontrar uma propriedade com o mesmo na Cadeia de Protótipos . O final da cadeia de protótipos é o Object.prototype.

console.log(o.toString === Object.prototype.toString); // logs true
   // which means we we're looking up the Prototype Chain and it reached 
   // the Object.prototype and used the "toString" method.

26. O que é um IIFE , para que serve?

Uma expressão de função IIFE ou Immediately Invoked Function Expression é uma função que será chamada ou executada após sua criação ou declaração. A sintaxe para criar o IIFE é que colocamos function (){} entre parênteses () ou o Operador de agrupamento para tratar a função como uma expressão e depois a invocamos com outros parênteses (). Portanto, um IIFE se parece com isso (function(){})().

(function () {

}());

(function () {

})();

(function named(params) {

})();

(() => {

})();

(function (global) {

})(window);

const utility = (function () {
   return {
      //utilities
   };
})();

Estes exemplos são todos IIFE válidos . O segundo ao último exemplo mostra que podemos passar argumentos para uma função IIFE . O último exemplo mostra que podemos salvar o resultado do IIFE em uma variável para que possamos fazer referência posteriormente.

O melhor uso do IIFE é tornar as funcionalidades de configuração de inicialização e evitar nomear colisões com outras variáveis no escopo global ou poluir o espaço para nome global. Vamos dar um exemplo.

<script src="https://cdnurl.com/somelibrary.js"></script>

Suponha que tenhamos um link para uma biblioteca somelibrary.js que expõe algumas funções globais que usamos no nosso código, mas essa biblioteca possui dois métodos que não usados createGraphe drawGraph porque esses métodos possuem bugs. E nós queremos implementar nossa própria createGraphe drawGraphx.

Uma maneira de resolver isso é alterando a estrutura de nossos scripts.

<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function createGraph() {
      // createGraph logic here
   }
   function drawGraph() {
      // drawGraph logic here
   }
</script>

Quando usamos essa solução, estamos substituindo os dois métodos que a biblioteca nos fornece.

Outra maneira de resolver isso é alterando o nome de nossas próprias funções auxiliares.

<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function myCreateGraph() {
      // createGraph logic here
   }
   function myDrawGraph() {
      // drawGraph logic here
   }
</script>

Quando usamos essa solução, também alteramos essas chamadas de função para os novos nomes de função.

Outra maneira é usar um IIFE .

<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   const graphUtility = (function () {
      function createGraph() {
         // createGraph logic here
      }
      function drawGraph() {
         // drawGraph logic here
      }
      return {
         createGraph,
         drawGraph
      }
   })
</script>

Nesta solução, estamos criando uma variável de utilitário que é o resultado do IIFE que retorna um objeto que contém dois métodos createGraphe drawGraph.

Outro problema que o IIFE resolve está neste exemplo.

var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   li[i].addEventListener('click', function (e) {
      console.log(i);
   })
}

Suponha que tenhamos um ul elemento com uma classe de lista-grupo e tenha 5 li elementos filhos. E queremos que o console.logo do valor i quando clicamos em um elemento individual li.

Mas o comportamento que queremos neste código não funciona. Em vez disso, ele registra qualquer clique em um li. O problema que estamos enfrentando é devido ao modo como os closure funcionam. Os closure são simplesmente a capacidade das funções de lembrar as referências de variáveis em seu escopo atual, no escopo da função pai e no escopo global. Quando declaramos variáveis usando a var palavra - chave no escopo global, obviamente estamos criando uma variável globa li. Portanto, quando clicamos em um li, ele registra, porque esse é o valor de i quando o referenciamos posteriormente na função de retorno de chamada.

Uma solução para isso é um IIFE .

var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   (function (currentIndex) {
      li[currentIndex].addEventListener('click', function (e) {
         console.log(currentIndex);
      })
   })(i);
}

Essa solução funciona devido ao motivo pelo qual o IIFE cria um novo escopo para cada iteração e capturamos o valor i e passamos para o parâmetrocurrentIndex, para que o valor de currentIndex seja diferente para cada iteração quando invocamos o IIFE .

27. Qual é o Function.prototype.apply método de uso ?

Os apply invoca uma função especificando o this ou o objeto "dono" de uma função.

const details = {
  message: 'Hello World!'
};

function getMessage(){
  return this.message;
}

getMessage.apply(details); // returns 'Hello World!'

Esse método funciona como Function.prototype.call a única diferença é como passamos os argumentos. Em apply nós passamos argumentos como uma matriz.

const person = {
  name: "LinuxUpdate"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.apply(person, ['Hello']); // returns "Hello LinuxUpdate!"

28. Qual é o método de uso da função Function.prototype.call ?

O argumento call invoca uma função especificando o this ou o objeto "dono" de uma função em seu tempo de invocação.

const details = {
  message: 'Olá Dev!'
};

function getMessage(){
  return this.message;
}

getMessage.call(details); // returns 'Olá Dev!'

Esse método funciona como Function.prototype.apply a única diferença é como passamos argumentos. Com call passamos diretamente os argumentos separandos com uma vírgula , para cada argumento.

const person = {
  name: "LinuxUpdate"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.call(person, 'Hello'); // returns "Hello LinuxUpdate!"
  1. Qual é a diferença entre Function.prototype.apply e Function.prototype.call?

A única diferença entre apply e call é como passamos os argumentos na função que está sendo chamada. Com apply passamos os argumentos como uma matriz e em call passamos os argumentos diretamente na lista de argumentos.

const obj1 = {
 result:0
};

const obj2 = {
 result:0
};

function reduceAdd(){
   let result = 0;
   for(let i = 0, len = arguments.length; i < len; i++){
     result += arguments[i];
   }
   this.result = result;
}

reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // returns 15
reduceAdd.call(obj2, 1, 2, 3, 4, 5); // returns 15

30. Para que serve Function.prototype.bind?

O bind retorna uma nova função vinculada a um valor this específico ou ao objeto "owner", para que possamos usá-lo posteriormente em nosso código. Os argumentos call, apply são métodos que invoca a função imediatamente ao invés de retornar uma nova função como o bind.

import React from 'react';

class MyComponent extends React.Component {
     constructor(props){
          super(props); 
          this.state = {
             value : ""
          }  
          this.handleChange = this.handleChange.bind(this); 
          //Vincula o método "handleChange" ao componente "MyComponent"
     }

     handleChange(e){
       //faça algo aqui
     }

     render(){
        return (
              <>
                <input type={this.props.type}
                        value={this.state.value}
                     onChange={this.handleChange}                      
                  />
              </>
        )
     }
}
Deixe uma resposta
You May Also Like