context this in function arrow with prototype

7

In the following example I have a class and add two functions by prototype the first as defined by funcion normalmente , while the second with arrow function

simpleClase = function(){
  this.ejemplo = 1
}
simpleClase.prototype.simple = function(){
  console.log(this)
}
simpleClase.prototype.arrow = () =>{
console.log(this)
   }
 
let nuevaClase = new simpleClase();
nuevaClase.simple();
nuevaClase.arrow();

The fact is that for the function as it is normally defined with prototype, it returns the contexto de la clase , while using arrow function it returns window

With another example:

class Clase  {
  constructor(){
  this.valor = 1

  }
  arrow() {
    let miFuncion= () => console.log("arrow" , this);
    miFuncion();
  }
  simple(){
    console.log("simple" , this);
  }
}
let miClase = new Clase();
miClase.arrow()
miClase.simple()

It gives me back the context of the class, this gives me the doubt of how prototype works with arrow function my doubt is because these areas are different, because the prototype does not takes the scope of the variable

    
asked by JackNavaRow 02.02.2018 в 02:51
source

2 answers

6

TL; DR:

let f=() => {...};

is equivalent to

let f= (function () {...}).bind(this);

Explanation with more examples:

Let's see how the arrow function works and how it defines its context. But first let's look at a normal function and its behavior:

let obj= { id: "obj"}; //creamos un objeto

function algo () { //creamos una función simple
  if (this) console.log(this.id);
  else console.log(this);
}
id="window";
algo(); //el contexto es window

obj.metodo=algo;
obj.metodo(); //el contexto es obj.

The context of the function varies according to its name.

This could be avoided with the bind method of the Function class:

let obj= { id: "obj"}; //creamos un objeto

function algo () { //creamos una función simple
  if (this) console.log(this.id);
  else console.log(this);
}

let algomas=algo.bind(obj); //fijamos el contexto: SIEMPRE será obj

id="window";
algo(); //el contexto es window

algomas();

Well, an arrow function is the equivalent of using .bind (this) at the time of the declaration:

class MiClase {

  constructor() {
    this.id="hola"
  }
  
  metodo() {
   let arrow= () => console.log(this);
   arrow();
  }
}

let obj= new MiClase();
obj.metodo();

Using classical notation to create a class:

function saludar() {
  console.log(this.a);
}
window.a="Window";

function ClaseA() { this.a="hola";}

function ClaseB() {this.a = "hola Clase2"}

ClaseA.prototype.saluda = saludar
ClaseB.prototype.saluda = saludar

let a = new ClaseA();
let b = new ClaseB();

a.saluda(); 
b.saluda();
saludar();

As you can see, a classic function receives the context at runtime, whatever it's called.

Using the arrow function

function Clase() { this.a="hola";}

Clase.prototype.saluda=function() {
  console.log(this.a);
}

let s=new Clase();


window.a="Window";


console.log("Contexto actual es:",this.a);
let arrow= ()=> console.log("Arrow",this.a); //el contexto actual se queda fijado para arrow

arrow();

Clase.prototype.saludosArrow= () => console.log("Arrow",this.a); //el contexto actual sigue fijandose!

s.saludosArrow();

Instead, an arrow function defines it at the time of the declaration.

    
answered by 02.02.2018 / 14:15
source
6

It's not that the arrow functions do not have access to this . If they have them, only that they have access to the environment that surround them or father. The documentation says:

  

An arrow function does not have this one ; this value is used   attached execution context (envelope)

Imagine that within a class, you define a private class, whatever the reason. Now, in the private class you have a function in prototype defined in the form of an arrow and from that function you need to access the properties of your own instance:

function Persona()
{
  this.nombre = "einer";
  
  function Corazon(){
      this.latidosPorSegundos = 4;
  }
    
  Corazon.prototype.latir = ()=>{
    console.log(this.latidosPorSegundos);
    console.log(this);    
  };
  
  var corazon = new Corazon();
  corazon.latir();
}

new Persona();

Note as corazon.latir() instead of printing 4, showing undefined and in this showing the definition of person. This is because this provides access to the parent (wrapper) scope, which would be Persona .

In your case, when you define a class in the global scope and create an instance of it, the parent scope of that instance is Window , not the instance of the object. As in the case of the example, the father field (envelope) of the prototype of the private class Corazon , is Persona .

Let's look at the areas like a box. this in the arrow functions provides access to the scope that surrounds them and as this is in Corazon , only give access to Persona , not window, since Corazon is within Persona :

 ---------------------------
|           Window          |
|   ---------------------   |
|   |      Persona       |  |
|   |  ---------------   |  |
|   |  |              |  |  |
|   |  |    Corazon   |  |  |
|   |  |              |  |  |
|   |   -------------    |  |
|   ---------------------   |
|                           |
 --------------------------

But in your case, I would navigate to the window since it has no other scope to wrap it:

 --------------------
|      Window        |
|  ---------------   |
|  |              |  |
|  |  simpleClase |  |
|  |              |  |
|   -------------    |
 --------------------
    
answered by 02.02.2018 в 14:33