this

  • Enlace amigable (slug) de la revisión: JavaScript/Reference/Operators/this
  • Título de la revisión: this
  • Id de la revisión: 302421
  • Creada:
  • Creador: carloshs92
  • ¿Es la revisión actual? No
  • Comentario

Contenido de la revisión

Introducción

Una palabra clave de función this se comporta un poco diferente en Javascript a comparación de otros lenguajes. Además tiene algunas diferencias entre el modo estricto y el modo no estricto.

En general, el objeto unido a this en el ámbito actual es determinado por como la actual función fue llamada, esto no puede ser cambiada por asignación durante la ejecución, y esto puede ser diferente cada vez que la función es llamada. ES5 introduce el método bind para arreglar el this de una función sin importar cómo es llamado.

Contexto global

En el contexto global (fuera de cualquier función), this refiere al objeto global, ya sea en modo estricto o no.

console.log(this.document === document); // true

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

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

Función contexto

Cuando la palabra clave this se produce dentro de una función, su valor depende de cómo se llama la función.

Llamada simple

function f1(){
  return this;
}

f1() === window; // objeto global


function f2(){
  "use strict"; // consultar modo estricto
  return this;
}

f2() === undefined;
Nota: En el segundo ejemplo, this debería ser undefined, porque f2 fue llamado sin proporcionar ninguna base(e.g. window.f2()). Esta característica no fue implementada en algunos navegadores cuando comenzaron a dar soporte al modo estricto; debido a esto, se retorna incorrectamente el objeto window.

Como un método de objeto

Cuando una función es llamada como un método de un objeto, el this cambia por el metodo del objeto llamado.

En el siguiente ejemplo, cuando o.f() es invocado, dentro de la función this es ligado al objeto o.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

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

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

Esto demuestra que sólo importa que la función fue invocada del elemento f de o.

Asimismo, el enlace this sólo se ve afectado por la referencia del elemento inmediata. En el siguiente ejemplo, cuando invocamos a la función, lo llamamos como metodo g del objeto o.b. Esta vez durante la ejecución, this dentro de la función se referirá a o.b. El hecho de que el objeto es en sí mismo un elemento de o no tiene ninguna consecuencia, la referencia más inmediata es todo lo que importa.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

... en la cadena de prototipo

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, this refiere al método del objeto cual fue llamado, como si el método fuese el objeto.

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

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

... o como un getter o setter

Nuevamente, el mismo concepto es válido cuando una función es invocado de un getter o un setter. Una función usado como getter o setter tiene su enlace this al objeto desde el cual la propiedad esta siendo set o gotten.

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

Como un constructor

Cuando una función es usada como un constructor (con la palabra clave new ), su this 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 done el valor de retorno sea un objeto.

/*
 * 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

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

call y apply

Cuando una función usa la plabra clave this en su cuerpo, su valor puede ser enlazado a un objeto particular durante la ejecuón del método  call or apply que todas las funciones hereden de  Function.prototype.

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

Funciones bound

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

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

Como un controlador de eventos DOM

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

// 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<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

Fuente de la revisión

<h2 id="Introducci.C3.B3n">Introducción</h2>
<p>Una palabra clave de función <code>this</code> se comporta un poco diferente en Javascript a comparación de otros lenguajes. Además tiene algunas diferencias entre el <a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode" title="en-US/docs/JavaScript/Strict mode">modo estricto</a> y el modo no estricto.</p>
<p>En general, el objeto unido a <code>this</code> en el ámbito actual es determinado por como la actual función fue llamada, esto no puede ser cambiada por asignación durante la ejecución, y esto puede ser diferente cada vez que la función es llamada. ES5 introduce el método <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind" title="en-US/docs/JavaScript/Reference/Global_Objects/Function/bind">bind</a></code> para <a href="/en-US/docs/JavaScript/Reference/Operators/this#Bound_functions" title="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Special/this#Bound_functions">arreglar el </a><a href="/en-US/docs/JavaScript/Reference/Operators/this#Bound_functions" title="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Special/this#Bound_functions"><code>this</code></a><a href="/en-US/docs/JavaScript/Reference/Operators/this#Bound_functions" title="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Special/this#Bound_functions"> de una función sin importar cómo es llamado.</a></p>
<h2 id="Contexto_global">Contexto global</h2>
<p>En el contexto global (fuera de cualquier función), <code>this</code> refiere al objeto global, ya sea en modo estricto o no.</p>
<div style="margin-right:270px;">
  <pre class="brush:js">
console.log(this.document === document); // true

// En el navegador 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>
<h2 id="Funci.C3.B3n_contexto">Función contexto</h2>
<p><span id="result_box" lang="es" tabindex="-1"><span class="hps">Cuando la palabra clave</span> </span><code>this </code><span id="result_box" lang="es" tabindex="-1"><span class="hps">se produce</span> <span class="hps">dentro de una función</span><span>, su valor</span> <span class="hps">depende de cómo</span> <span class="hps">se llama la función</span><span>.</span></span></p>
<h3 id="Llamada_simple">Llamada simple</h3>
<pre class="brush:js">
function f1(){
  return this;
}

f1() === window; // objeto global


function f2(){
  "use strict"; // consultar modo estricto
  return this;
}

f2() === undefined;
</pre>
<div class="note">
  <strong>Nota:</strong> En el segundo ejemplo, <code>this</code> debería ser <a href="/en-US/docs/JavaScript/Reference/Global_Objects/undefined" title="undefined"><code>undefined</code></a>, porque <code>f2</code> fue llamado sin proporcionar ninguna base(e.g. <code>window.f2()</code>). Esta característica no fue implementada en algunos navegadores cuando comenzaron a dar soporte al <a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode" title="Strict mode">modo estricto</a>; debido a esto, se retorna incorrectamente el objeto window.</div>
<h3 id="Como_un_m.C3.A9todo_de_objeto">Como un método de objeto</h3>
<p>Cuando una función es llamada como un método de un objeto, el <code>this</code> cambia por el metodo del objeto llamado.</p>
<p>En el siguiente ejemplo, cuando <code>o.f()</code> es invocado, dentro de la función <code>this</code> es ligado al objeto <code>o</code>.</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 donde la función fue definida. En el ejemplo anterior, nosotros definimos la función&nbsp; en línea como el elemnto <code>f</code> durante la definición de <code>o</code>.&nbsp; Sin embargo, podriamos haber definido con la misma facilidad la primera función y luego&nbsp; 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 elemento 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" tabindex="-1"><span class="hps">El hecho de que</span> <span class="hps">el objeto</span> <span class="hps">es en sí mismo</span> <span class="hps alt-edited">un elemento</span> <span class="hps">de </span></span><code>o</code><span id="result_box" lang="es" tabindex="-1"> <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> refiere al método del objeto cual fue llamado, como si el método fuese el 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 <a href="/Prototype" title="Prototype">prototipo</a>. 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 carácteristica 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 invocado 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 set o gotten.</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 <code><a href="/en-US/docs/JavaScript/Reference/Operators/new" title="new">new</a></code> ), 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 done 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 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 ejecuón del método&nbsp; <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global_Objects/Function/call">call</a></code> or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global_Objects/Function/apply">apply</a></code> que todas las funciones hereden de&nbsp; <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_bound">Funciones bound</h3>
<p>ECMAScript 5 introduce <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind" title="en-US/docs/JavaScript/Reference/Global Objects/Function/bind">Function.prototype.bind</a></code>.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 conotros 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>
Revertir a esta revisión