aboutsummaryrefslogtreecommitdiff
path: root/files/es/web/javascript/referencia/operadores/this/index.html
blob: 74ed62bb60ab2617849c04913dbeb2bdb3993682 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
---
title: this
slug: Web/JavaScript/Referencia/Operadores/this
translation_of: Web/JavaScript/Reference/Operators/this
---
<div>{{jsSidebar("Operators")}}</div>

<h2 id="Introducción">Introducción</h2>

<p>La palabra clave <strong><code>this</code></strong> de una función se comporta un poco diferente en Javascript en comparación con otros lenguajes. Además tiene algunas diferencias entre el <a href="/es/docs/Web/JavaScript/Referencia/Funciones/Modo_estricto" title="en-US/docs/JavaScript/Strict mode">modo estricto</a> y el modo no estricto.</p>

<p>En general, el valor de <code>this</code> está determinado por cómo se invoca a la función. No puede ser establecida mediante una asignación en tiempo de ejecución, y puede ser diferente cada vez que la función es invocada. ES5 introdujo el método {{jsxref("Function.bind()", "bind()")}} para <a href="#Funciones_enlazadas" title="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Special/this#Bound_functions">establecer el valor de la función <code>this</code> independientemente de como es llamada</a>, y ES2015 introdujo las <a href="/es/docs/Web/JavaScript/Referencia/Funciones/Arrow_functions">funciones flecha</a> que no proporcionan su propio "binding" de <code>this</code> (se mantiene el valor de <code>this</code> del contexto léxico que envuelve a la función)</p>

<p>{{EmbedInteractiveExample("pages/js/expressions-this.html")}}</p>

<h2 id="Sintaxis">Sintaxis</h2>

<pre class="syntaxbox">this</pre>

<h3 id="Valor">Valor</h3>

<p>El objeto contexto de JavaScript en el cual se está ejecutando el código actual.</p>

<h2 id="Contexto_global">Contexto global</h2>

<p>En el contexto de ejecución global (fuera de cualquier función), <strong><code>this</code></strong> se refiere al objeto global, ya sea en modo estricto o no.</p>

<pre class="brush:js">console.log(this.document === document); // true

// En los navegadores web, el objeto window también es un objeto global:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37
</pre>

<div class="blockIndicator note">
<p><font><font>Nota: Puedes obtener el objeto global usando la propieda global <code>globalThis</code>, no importa el contexto donde se ejecute esta propiedad, siempre hará referencia al objeto global. </font></font></p>
</div>

<h2 id="Contexto_de_la_función">Contexto de la función</h2>

<p><span class="hps" style="line-height: 1.5;">Dentro de una</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">función</span><span style="line-height: 1.5;">, </span><span class="hps" style="line-height: 1.5;">el valor de this</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">depende de cómo</span><span style="line-height: 1.5;"> la función es l</span><span class="hps" style="line-height: 1.5;">lamada</span><span id="result_box" lang="es" style="line-height: 1.5;">.</span></p>

<h3 id="Llamada_simple">Llamada simple</h3>

<pre class="brush:js">function f1(){
  return this;
}

f1() === window; // objeto global
</pre>

<div><span class="hps" style="line-height: 1.5;">En</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">este caso</span><span style="line-height: 1.5;">,</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">el valor de <strong>this</strong></span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">no está establecido</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">por</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">la llamada</span><span style="line-height: 1.5;">.</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">Dado que el código</span><span style="line-height: 1.5;"> </span><span class="alt-edited hps" style="line-height: 1.5;">no está</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">en modo estricto</span><span style="line-height: 1.5;">, </span><span class="hps" style="line-height: 1.5;">el valor de this</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">debe ser siempre</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">un objeto</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">por lo que</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">por defecto es el</span><span style="line-height: 1.5;"> </span><span class="hps" style="line-height: 1.5;">objeto global</span><span style="line-height: 1.5;">.</span></div>

<div></div>

<div>
<pre class="brush:js" style="font-size: 14px;">function f2(){
  "use strict"; // consultar modo estricto
  return this;
}

f2() === undefined;</pre>
</div>

<div><span style="line-height: 1.5;">En modo estricto, el valor de <strong>this</strong> se mantiene en lo que está establecida al entrar en el contexto de ejecución. Si no está definido, permanece undefined. También se puede ajustar a cualquier valor, tales como <strong>null</strong> o <strong>42</strong> o "<strong>Yo no soy this</strong>".</span></div>

<div></div>

<div class="note">
<p><strong>Nota:</strong> En el segundo ejemplo, <strong><code>this</code></strong> debería ser {{jsxref("undefined")}}, porque <code>f2</code> fue llamado sin proporcionar ninguna base (ej. <code>window.f2()</code>). Esta característica no fue implementada en algunos navegadores cuando se comenzó a dar soporte al <a href="/es/docs/Web/JavaScript/Referencia/Funciones/Modo_estricto" title="Strict mode">modo estricto</a>. Como resultado, retorna incorrectamente el objeto window.</p>
</div>

<div><span>Como un método de un objeto</span></div>

<p>Cuando una función es llamada como un método de un objeto, el <strong><code>this</code></strong> cambia por el metodo del objeto llamado.</p>

<p>En el siguiente ejemplo, cuando <strong><code>o.f()</code></strong> es invocado, dentro de la función <strong><code>this</code></strong> es ligado al objeto <strong><code>o</code></strong>.</p>

<pre class="brush:js">var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37
</pre>

<p>Note que el comportamiento no es del todo afectado por cómo o dónde la función fue definida. En el ejemplo anterior, nosotros definimos la función en línea como el elemento <code>f</code> durante la definición de <code>o</code>.  Sin embargo, podriamos haber definido con la misma facilidad la primera función y luego  adjuntarlo a <code>o.f</code>. Hacerlo da como resultado el mismo comportamiento.</p>

<pre class="brush:js">var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37
</pre>

<p>Esto demuestra que sólo importa que la función fue invocada del elemento <code>f</code> de <code>o</code>.</p>

<p>Asimismo, el enlace <code>this</code> sólo se ve afectado por la referencia del miembro más inmediata. En el siguiente ejemplo, cuando invocamos a la función, lo llamamos como metodo <code>g</code> del objeto <code>o.b</code>. Esta vez durante la ejecución, <code>this </code>dentro de la función se referirá a <code>o.b</code>. <span id="result_box" lang="es"><span class="hps">El hecho de que</span> <span class="hps">el objeto</span> <span class="hps">es en sí mismo</span> <span class="alt-edited hps">un elemento</span> <span class="hps">de </span></span><code>o</code><span id="result_box" lang="es"> <span class="hps">no tiene ninguna</span> <span class="hps">consecuencia</span><span>,</span> <span class="hps">la referencia más</span> <span class="hps">inmediata es</span> <span class="hps">todo lo que importa</span><span>.</span></span></p>

<pre class="brush:js">o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
</pre>

<h4 id="..._en_la_cadena_de_prototipo">... en la cadena de prototipo</h4>

<p>El mismo concepto es válido para los métodos definidos en alguna parte de la cadena de prototipo del objeto. Si el método esta sobre una cadena de prototipo del objeto, <code>this</code> se referirá al objeto donde está el método de donde fue llamado. Como si ese método estuviera dentro del objeto. </p>

<pre class="brush:js">var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5
</pre>

<p>En este ejemplo, el objeto asignado a la variable <code>p</code> no tiene su propia propiedad <code>f</code>, esto lo hereda de su prototipo. Pero no importa que la búsqueda de <code>f</code> eventualmente encuentre un elemento con ese nombre en <code>o</code>; la búsqueda comenzó como una referencia a <code>p.f</code>, asi <code>this </code>dentro de la funcion toma el valor del objeto referido como <code>p</code>. Es decir, desde que <code>f</code> es llamado como método de <code>p</code>, su <code>this</code> refiere a <code>p</code>. Esto es una interesante característica de la herencia de prototipo de JavaScript.</p>

<h4 id="..._o_como_un_getter_o_setter">... o como un getter o setter</h4>

<p>Nuevamente, el mismo concepto es válido cuando una función es invocada de un getter o un setter. Una función usado como getter o setter tiene su enlace <code>this</code> al objeto desde el cual la propiedad esta siendo establecida u obtenida.</p>

<pre class="brush:js">function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142
</pre>

<h3 id="Como_un_constructor">Como un constructor</h3>

<p>Cuando una función es usada como un constructor (con la palabra clave {{jsxref("Operadores/new", "new")}}), su <code>this</code> es enlazado al nuevo objeto en construcción, a menos que la ejecución de los resultados del constructor en el motor JavaScript encuentren una instrucción de retorno donde el valor de retorno sea un objeto.</p>

<pre class="brush:js">/*
 * Los constructores trabajan algo asi:
 *
 * function MyConstructor(){
 *   // El cuerpo del código de la función actual va aquí.  Crear las propiedades en |this| como
 *   // se desee mediante la asignación a los mismos.  E.g.,
 *   this.fum = "nom";
 *   // etcetera...
 *
 *   // Si la función tiene una sentencia de retorno este retorna un objeto,
 *   // este objeto será el resultado de la expresión |new|.  Por otro lado, el
 *   // resultado de la expresión es el objeto actualmente enlazado a |this|
 *   // (i.e., el caso más común suele verse).
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38
</pre>

<p>En el último ejemplo (<code>C2</code>), debido a que un objeto fue devuelto durante la construcción, el nuevo objeto que fue enlazado a <code>this</code> simplemente se descarta.( Esto esencialmente hace de la declaración "<code>this.a = 37;</code>" codigo muerto. No esta exactamente muerto,porque es ejecutado pero se puede eliminar sin efectos externos.)</p>

<h3 id="call_y_apply"><code>call</code> y <code>apply</code></h3>

<p>Cuando una función usa la plabra clave <code>this</code> en su cuerpo, su valor puede ser enlazado a un objeto particular durante la ejecución del método {{jsxref("Function.call()", "call()")}} or {{jsxref("Function.apply()", "apply()")}} que todas las funciones hereden de  <code>Function.prototype</code>.</p>

<pre class="brush:js">function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

// El primer parámetro es el objeto a usar como 'this', parámetros posteriores se pasan como argumentos
// en la llamada a la función
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

//El primer parámetro es el objeto a usar como 'this''this', la segunda es una matriz cuyos elementos
//  se utilizan como argumentos en la llamada a la función
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
</pre>

<h3 id="Funciones_enlazadas">Funciones enlazadas</h3>

<p>ECMAScript 5 introduce {{jsxref("Function.prototype.bind()")}}. Llamando a <code>f.bind(someObject)</code> crea una nueva función con el mismo cuerpo y alcance de <code>f</code>, pero donde <code>this</code> se produce en la función original, en la nueva función esto esta permanentemente ligado al primer argumento de <code>bind</code>, independientemente de cómo la función está siendo utilizada.</p>

<pre class="brush:js">function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty
</pre>

<h3 id="Como_un_controlador_de_eventos_DOM">Como un controlador de eventos DOM</h3>

<p>Cuando una función es usada como un controlador de eventos, su <code>this</code> es cambiado desde el elemento del evento disparado (algunos navegadores no siguen esta convención para los listeners agregados dinámicamente con otros métodos <code>addEventListener</code>).</p>

<pre class="brush:js">// Cuando se llama como un listener, convierte en azul el elemento
// relacionado
function bluify(e){
  console.log(this === e.currentTarget); // Siempre true
  console.log(this === e.target);        // true cuando currentTarget y target son el mismo objeto
  this.style.backgroundColor = '#A5D9F3';
}

// Consigue una lista de cada elemento en un documento
var elements = document.getElementsByTagName('*');

// Añade bluify como un click listener asi cuando se hace click sobre el elemento,
// este cambia a azul
for(var i=0 ; i&lt;elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}</pre>