When trying to create an object using `this` the console says that the property is Undefined

Asked

Viewed 166 times

4

I’m learning to use objects in Javascript, and I stumbled upon an unforeseen behavior in my object. In the case when I try to store an element via DOM within a property the console says that the property is undefined:

TypeError: this.seletorTimer is undefined [Learn More]

Screenshot of the console error

let Inicial = {
  seletorTimer: document.getElementById("TimerInicial"),
  letrasRegex: /[A-Z]+/,
  maximo: 59,
  SemLetras: this.seletorTimer.addEventListener('keyup', () => {
    if (document.getElementById("TimerInicial").value.match(this.letrasRegex)) {
      this.seletorTimer.value = "";
    }
  }),
  numeroLimite: document.getElementById("TimerInicial").addEventListener('keyup', () => {
    if (this.seletorTimer.value > this.maximo) {
      this.seletorTimer.value = 59;
    }
  }),
};

Online code in jsfiddle

What I’m trying to do in this code is basically not allow the user to type letters or symbols (just numbers) and when the user puts a value greater than 59, the event rewrites the input value to 59. I confess that I do not know if it is possible to make an object this way because the question of the scope is a little confused for me.

  • 1

    Ola @Daniel, you could improve your question ( I couldn’t understand it -- [Ask] ), it is only worth you to put the error that appeared on the console, it can help the community to solve their doubt. = P -- don’t forget to take a look at our [Tour] =D

  • 1

    @Icaromartins I’m not in the habit of asking in the Stack, I tried to give a fancy in the question, I hope it is more readable kkk

  • Also add your code here as text and not as image or link

  • Truth thank you @Costamilam!

  • @Danielkenzi, I’ve changed the title of your question, because I believe that way you can help other people. If you feel that I have changed the meaning of your original question please access this link (revisions) and click on reverse in the version you think best. = D

  • @Icaromartins is excellent hahaha. After the explanation you gave really makes more sense, Rigadão!

Show 1 more comment

1 answer

6


Part of your problems and understanding some things in your code, the first one I see is your understanding of the this.

The this is the object of execution context, its use is a little complicated to understand even, but once you understand its use it becomes very useful, so I will try to explain you below using comments in the code:

/// ; neste momento o `this` === `window`
console.log( 'this é igual a window ? ',  this === window );


var elTimerInicial = document.getElementById("TimerInicial");


let Inicial = {
  seletorTimer: elTimerInicial,
  letrasRegex: /[A-Z]+/,
  maximo: 59,

  /// ; Neste momento o this ainda é `window` e nele não existe
  /// ; a propriedade `selectorTime`, você esta pensando que nesse
  /// ; momento o `this` era o objeto `Inicial` e por isso estava chamando
  /// ; `this.seletorTimer`.
 
  /// ; Outra coisa que acontece é que neste momento o objeto
  /// ; `Inicial` ainda não foi criado, ou seja, você também não
  /// ; conseguiria acessar usando `Inicial.selectorTime`


  SemLetras: elTimerInicial.addEventListener('keyup', function(){
      
      /// ; Agora complica um pouco, note que eu troquei seu 
      /// ; `Arrow Function` por um `Function normal`.
      /// ; Quando esse evento é disparado o `this` aqui vai ser o
      /// ; elemento que disparou o evento ou seja, nesse caso o `elTimerInicial`

      console.log( 'Function Normal,  this é igual a window ? ', this === window, this );

  }),

  numeroLimite: elTimerInicial.addEventListener('keyup', () => {
  
      /// ; Aqui eu mantive o `Arrow Function` para você ver a diferença
      /// ; ele NÃO cria contexto, então aqui dentro
      /// ; o `this` é o mesmo que era fora dele quando ele 
      /// ; foi criado, ou seja, o `window`.
      /// ; Esse é um dos motivos que levaram ao desenvolvedores
      /// ; a criar esse novo tipo de função, veja um
      /// ; exemplo prático na sessão 'alguns problemas comuns com this'.
      
      console.log( 'Arrow Function,  this é igual a window ? ', this === window );

  }),
};
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Guessing game</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" media="screen" href="style.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
</head>
<body>
    <h1>PROJETO TIMER</h1>
    <div id="TimerInicial">
        <input type="number"  placeholder="HH" > :
        <input type="number"  placeholder="MM" > :
        <input type="number"  placeholder="SS" >
    </div>
</body>
</html>


Another problem is that in your code you’re trying to catch value of the element #TimerInicial which is a <div> and not the <input> you’re getting the value. So in the code below we will try to use the this and change your object.

var elTimerInicial = document.getElementById("TimerInicial");

/// ; ao invés de criar um objeto vamos usar o próprio `elTimerInicial` 

elTimerInicial.letrasRegex = /[A-Z]+/;
elTimerInicial.maximo = 59;
elTimerInicial.semLetras = function( input ){
    
    /// ; Quando você chamar essa função desta forma `elTimerInicial.semLetras( )`
    /// ; `this` aqui sera o próprio `elTimerInicial`

    console.log( '2- semLetras - this:' , this, ' input:' , input ); 

    if( input.value.match(this.letrasRegex) ){
        input.value = "";
    }

};
elTimerInicial.numeroLimite = function( input ){

     console.log( '3- numeroLimite - this:' , this, ' input:' , input );

     if ( input.value > this.maximo ) {
          input.value = 59;
     }

};


/// ; Como só os `input`s são filhos do `elTimerInicial` vamos usar a propriedade
/// ; `children` do `elTimerInicial` para pegar seu filhos e adicionar o evento neles
/// ; depois vamos usar o `this` novamente dentro da função:

for( var i = 0, max = 3; i < max ; i++ )
{

    elTimerInicial.children[ i ].addEventListener('keyup', function(){
        
        /// ; Quando essa funcao for chamada o `this` aqui dentro sera o `input`
        /// ; que disparou o evento.

        /// ; vamos usar o `parentNode` para pegar o pai desse `input` nesse caso o 
        /// ; `elTimerInicial` e vamos usar as funções que 
        /// ;  adicionamos a esse elemento `elTimerInicial`
        
        console.log( '1- keyup this:' , this, 'this.parentNode', this.parentNode );

        this.parentNode.semLetras( this );
        this.parentNode.numeroLimite( this );
        /// ;    ^          ^          ^ this === input 
        /// ;    |          função que adicionamos ao `elTimerInicial`
        /// ;    elTimerInicial

    });

}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Guessing game</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" media="screen" href="style.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
</head>
<body>
    <h1>PROJETO TIMER</h1>
    <div id="TimerInicial">
        <input type="number"  placeholder="HH" > :
        <input type="number"  placeholder="MM" > :
        <input type="number"  placeholder="SS" >
    </div>
</body>
</html>


Some common problems with the this

Fact is, when you’re wearing this how you call a function can change its context.

Imagine I have an object with the name mObject and in that object there is the method minhafuncao using the this hoping he’ll be the mObject.

Imagine that for some reason instead of calling mObject.minhafuncao() thus, namely of direct form, you need to call this function within a setTimeout, pass her off as a callback or associate this function to a variable to save time by typing etc... as in the example below:

var mObject = {
   minhafuncao:function(){
       console.log( 'this é:', this===window ? 'window' : this );
   }
};

/// ; Exemplo callback
function chamaCallback( callback ){
    callback();
}

chamaCallback( mObject.minhafuncao );

/// ; Exemplo associar a função a uma variável
var func = mObject.minhafuncao;
func();

/// ; Exemplo setTimeout
setTimeout( mObject.minhafuncao, 1 ); 

  

If this occurs you will realize that the this that this within the function nay will be the mObject he will be the window or some other unexpected context, now you may have noticed that this occurred because the context of the call has changed.

This can be easily solved with the use of apply, call, bind to manipulate the context or in the case of the example of setTimeout a simple function already solve, see the code below:

var mObject = {
   minhafuncao:function(){
       console.log( 'this é:', this===window ? 'window' : this );
   }
};

/// ; Exemplo associar a função a uma variável
var func = mObject.minhafuncao;

func.call( mObject );
/// ; func.call( mObject, parametro1, parametro2, ...  );
/// ;            ^        ^ os parâmetros da função começa aki
/// ;            contexto, isso sera o `this` dentro da função   


/// ; Exemplo setTimeout
setTimeout( function(){
 
    mObject.minhafuncao();
    /// ; o contexto dessa chamada voltou a ser o `mObject`        
 
}, 1 );


 /// ; Exemplos com o `bind`
 var novaFunc = mObject.minhafuncao.bind( mObject );
 /// ; bind retorna a função com o contexto sendo o parâmetro


 /// ; Agora quando eu chamar a função `novaFunc` ela vai manter o contexto
 /// ; Então essa chamada o `this` sera o `mObject`
 novaFunc();
 
 
 /// ; Chamando pela callback
 function chamaCallback( callback ){
     callback();
 }
 chamaCallback( novaFunc );     

 /// ; O mesmo ocorre com o `setTimeout` o contexto da função vai ser mantido
 /// ; por causa do `bind` então o `this` sera o `mObject`
 setTimeout( novaFunc, 1 );

 /// ; Ou seja com `bind`, `call`, `apply` você vai conseguir manipular o
 /// ; contexto e modificar como quiser veja esse outro exemplo:
 novaFunc = mObject.minhafuncao.bind( {name:"### Mudei o contexto totalmente ###"} );
 setTimeout( novaFunc, 10 );
 

Another example, imagine that you have a <div> in which you placed an event onClick, and you will use the this within the event to change the style, className, etc... of that <div> and after x time will return to normal, ie using a setTimeout within the event.

/// ; criar a div
var div = document.createElement('DIV');

/// ; adicionar ele ao body da pagina
document.body.appendChild( div );

/// ; colocar o texto e mudar style `bgcolor`
div.innerHTML = 'MEU TESTE';
div.style['backgroundColor'] = 'red';

/// ; adicionar o evento de onclick
div.onclick = function(){
    
    /// ; `this` quando esse evento for disparado sera a `<div>`
      
    this.style['backgroundColor'] = 'green';
    this.innerHTML = "eu cliquei aki";
  
    /// ; agora dentro da função do setTimeout o `this` será a `window`
    /// ; para solucionar esse problema alem das soluções já mostradas
    /// ; podemos associar o `this` a uma variável local dentro do
    /// ; evento e utilizar essa variável dentro do `setTimeout` veja abaixo

    var self = this;

    setTimeout( function(){
       
       console.log( 'settimeout this é:', this === window ? 'window':'outra coisa');

       self.style['backgroundColor'] = 'red';

    }, 600 );
    
    /// ; Outra solução seria o uso do `Arrow function` 
    /// ; isso porque como eu já disse antes um dos 
    /// ; objetivos dele é de NÃO criar contexto, então 
    /// ; o `this` dentro dele será o mesmo que era fora dele

    setTimeout( ()=>{ 

       console.log( 'arrow function this é:', this === window ? 'window': this);

        this.innerHTML = "MEU TESTE";

    }, 600);
}


Other links that may help

Links Sopt:

"this" a reliable reference?

What’s the difference between $(this) and $this and this?

What’s the THIS parameter for?

External Links:

codigosimples.net - Learn more about the "this" used javascript

Mozilla Developer Docs References:

Arrow functions, this, children, apply, call, bind

  • 1

    Our explained a lot about the use of this! And I didn’t know that you could insert properties in this way, very cool. The only question that came to me is whether the loop at the end is a good practice, because I was trying to use objects precisely to avoid creating global variables or letting "loose" addeventListeners. Good thank you very much for the reply!

  • The for in the end can be improved, an improvement would remove the creation of function from within it addEventListener('keyup', function(){ ... });, create the function outside the for for example function eventoKeyUp(){ ... } or elTimerInicial.eventoKeyUp=function(){ ... }, and switch to addEventListener('keyup', eventoKeyUp) or addEventListener('keyup', elTimerInicial.eventoKeyUp)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.