Because with Arrow functions the context is different from a common function?

Asked

Viewed 94 times

3

In the snippet I prepared below, I have a table with some simple data. Below the table, there are two Abels that account for the total age of the data in the table. The first label is calculated using a common anonymous function, the second is using an Arrow Function.

I realized, at Arrow Function, the this is Window, and not the object that called the function, as in the other case. Because of this, the sum on the label results in Nan (Not a Number)

Reading the documentation, I came to the concept of this But from then on, I didn’t understand anything. How could I get around the situation for Arrow Function to work the way I expected in these cases?

window.onload = function (){
  atualizaSomaIdades();
  atualizaSomaIdadesArrowFunction();
}

$('.excluir').click(function (){
  $(this).parent().parent().remove();
  atualizaSomaIdades();
  atualizaSomaIdadesArrowFunction();
});

function atualizaSomaIdades(){
  var total = 0;
  var rows = $('table').find('tbody').find('tr');
  rows.each(function () {
      total += parseInt($(this).find('td').eq(1).text());
  });
  $('#idade-comum').text(total);
}

function atualizaSomaIdadesArrowFunction(){
  var total = 0;
  var rows = $('table').find('tbody').find('tr');
  rows.each(() => {
    total += parseInt($(this).find('td').eq(1).text());
  });
  $('#idade-arrow-function').text(total);

}
td{
  border: 1px solid black;
}

.negrito{
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
  <tr>
    <td>Nome</td>
    <td>Idade</td>
    <td>Ações</td>
  </tr>
</thead>
<tbody>
  <tr>
    <td>
      João
    </td>
    <td>
      25
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
  <tr>
    <td>
      Carlos
    </td>
    <td>
      16
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
  <tr>
    <td>
      Artur
    </td>
    <td>
      21
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
</tbody>
</table>

<span class="negrito">Total de idade:</span>
<span id="idade-comum"></span>
<span id="idade-arrow-function"></span>

3 answers

1

The this lexicon in Arrow Function is very useful when working object-oriented in javascript (with classes for example). The MDN example is very practical:

function Pessoa(){
  this.idade = 0;

  setInterval(() => {
    this.idade++; // |this| corretamente referência ao objeto Pessoa
  }, 1000);
}

var p = new Pessoa();

For your case, so that this not take a more global context but rather the location of the function, you can indicate the element by changing in this way:

rows.each((index,elemento) => {

Example

window.onload = function (){
  atualizaSomaIdades();
  atualizaSomaIdadesArrowFunction();
}

$('.excluir').click(function (){
  $(this).parent().parent().remove();
  atualizaSomaIdades();
  atualizaSomaIdadesArrowFunction();
});

function atualizaSomaIdades(){
  var total = 0;
  var rows = $('table').find('tbody').find('tr');
  rows.each(function () {
      total += parseInt($(this).find('td').eq(1).text());
  });
  $('#idade-comum').text(total);
}

function atualizaSomaIdadesArrowFunction(){
  var total = 0;
  var rows = $('table').find('tbody').find('tr');
  rows.each((index,elemento) => {
    total += parseInt($(elemento).find('td').eq(1).text());
  });
  $('#idade-arrow-function').text(total);

}
td{
  border: 1px solid black;
}

.negrito{
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
  <tr>
    <td>Nome</td>
    <td>Idade</td>
    <td>Ações</td>
  </tr>
</thead>
<tbody>
  <tr>
    <td>
      João
    </td>
    <td>
      25
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
  <tr>
    <td>
      Carlos
    </td>
    <td>
      16
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
  <tr>
    <td>
      Artur
    </td>
    <td>
      21
    </td>
    <td>
      <button class="excluir">Remover</button>
    </td>
  </tr>
</tbody>
</table>

<span class="negrito">Total de idade:</span>
<span id="idade-comum"></span>
<span id="idade-arrow-function"></span>

0

You should use the concept of closures to get a direct reference to the thisfrom the external context to your Arrow Function.

Just capture the this in a variable and use this variable within the Arrow Function.

const self = this
rows.each(() => {
  total += parseInt($(self).find('td').eq(1).text());
});

Or you can use a function normal, that you yourself saw that captures the this automatically.

In case you wanted to learn more about closures:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

0

Adding to the previous responses, you can use the method bind to determine the context of this for duties:

rows.each((() => { total += parseInt($(this).find('td').eq(1).text()); }).bind(this));

Doc in Mozilla

The method bind takes as its first argument an object called thisArg, which is the context for this within this function. Thus, placing .bind(this) in an Arrow Function makes all the this are equal to this external to the scope of that function.

Browser other questions tagged

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