514 votos

JavaScript palabra "this"

Me he dado cuenta que no parece haber una explicación clara de lo que el this es la palabra clave y cómo es correctamente (y erróneamente) utilizado en JavaScript en el sitio de desbordamiento de pila.

Que han sido testigos de algún comportamiento extraño con él y no han podido entender por qué ha ocurrido.

¿Alguien quiere explicarme cómo this obras y cuándo se debe utilizar?

634voto

Daniel Trebbien Puntos 18089

Recomiendo la lectura de Mike West's artículo Alcance en JavaScript (espejo) en primer lugar. Es un excelente, amable introducción a los conceptos de this y el alcance de las cadenas en JavaScript.

Una vez que empiece a acostumbrarse this, las reglas son en realidad bastante simple. El Estándar ECMAScript define this como una palabra clave que "se evalúa al valor de la ThisBinding del contexto de ejecución actual" (§11.1.1). ThisBinding es algo que el intérprete de JavaScript mantiene como evalúa el código JavaScript, como un especial de registro de CPU que contiene una referencia a un objeto. El intérprete actualizaciones de la ThisBinding siempre que el establecimiento de un contexto de ejecución en uno de los tres casos diferentes:

  1. Inicial global del contexto de ejecución

    Este es el caso de el código JavaScript que se evalúa cuando un <script> elemento se encuentra:

    <script type="text/javascript">//<![CDATA[
    alert("I'm evaluated in the initial global execution context!");
    
    setTimeout(function () {
        alert("I'm NOT evaluated in the initial global execution context.");
    }, 1);
    //]]></script>
    

    Cuando la evaluación de código en el primer mundial en el contexto de ejecución, ThisBinding se establece en el objeto global, window (§10.4.1.1).

  2. Introducir código de eval

    • ... por una llamada directa a eval()

      ThisBinding se queda sin cambios; es el mismo valor que la ThisBinding de la vocación en el contexto de ejecución (artículo 10.4.2(2)(a)).

    • ... si no por una llamada directa a eval()

      ThisBinding se establece en el objeto global como si la ejecución en la fase inicial de ejecución global del contexto (§10.4.2(1)).

    §15.1.2.1.1 define lo que es un llamado directo a eval (). Básicamente, eval(...) es una llamada directa, mientras que algo como (0, eval)(...) o var indirectEval = eval; indirectEval(...); es una llamada indirecta a eval(). Ver chuckj la respuesta a (1,eval)('este') vs eval('este') en JavaScript? y esta entrada de blog por Dmitry Soshnikov para cuando se puede usar una indirecta eval() de la llamada.

  3. Entrar el código de la función

    Esto ocurre cuando se llama a una función. Si se llama a una función en un objeto, como en obj.myMethod() o el equivalente a obj["myMethod"](), luego ThisBinding se establece en el objeto (obj en el ejemplo; §13.2.1). En la mayoría de los otros casos, ThisBinding se establece en el objeto global (§10.4.3).

    La razón de escribir "en la mayoría de los casos" es porque hay ocho ECMAScript 5 funciones integradas que permiten ThisBinding ser especificados en la lista de argumentos. Estas funciones toman un llamado thisArg que se convierte en el ThisBinding al llamar a la función (§10.4.3).

    Estas funciones integradas son:

    • Function.prototype.apply( thisArg, argArray )
    • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
    • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
    • Array.prototype.every( callbackfn [ , thisArg ] )
    • Array.prototype.some( callbackfn [ , thisArg ] )
    • Array.prototype.forEach( callbackfn [ , thisArg ] )
    • Array.prototype.map( callbackfn [ , thisArg ] )
    • Array.prototype.filter( callbackfn [ , thisArg ] )


    En el caso de la Function.prototype funciones, que son llamados a un objeto de la función, pero más que ThisBinding a la función de objeto, ThisBinding se establece en el thisArg.

    En el caso de la Array.prototype funciones, la callbackfn se llama en un contexto de ejecución donde ThisBinding se establece en thisArg si es facilitado; de lo contrario, al objeto global.

Esas son las reglas de la llanura de JavaScript. Cuando usted comience a usar las bibliotecas de JavaScript (p. ej. jQuery), es posible que ciertas funciones de la biblioteca de manipular el valor de this. Los desarrolladores de esas bibliotecas de JavaScript de hacer esto porque se tiende a apoyar el uso más común de los casos, y los usuarios de la biblioteca suele encontrar a este comportamiento es más conveniente. Al pasar funciones de devolución de llamada de referencia this a las funciones de la biblioteca, usted debe referirse a la documentación de ninguna garantía sobre cuál es el valor de this es cuando se llama a la función.

Si usted se está preguntando cómo es una biblioteca de JavaScript que manipule el valor de this, la biblioteca es simplemente el uso de una de las integradas en las funciones de JavaScript aceptar un thisArg. Usted, también, puede escribir su propia función que recibe una función de devolución de llamada y thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

EDICIÓN:

Se me olvidó un caso especial. Cuando la construcción de un nuevo objeto a través de la new operador, el intérprete de JavaScript crea un nuevo objeto vacío, establece algunas propiedades internas, y luego llama a la función constructora en el nuevo objeto. Por lo tanto, cuando se llama a una función en un constructor contexto, el valor de this es el nuevo objeto de que el intérprete de creación:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

CONCURSO: Sólo por diversión, prueba de su entendimiento con los siguientes ejemplos.

Para revelar las respuestas, pase el ratón sobre los cuadros grises.

  1. ¿Cuál es el valor de this en línea? ¿Por qué?

    <script type="text/javascript">
    if (true) {
        // Line A
    }
    </script>
    

    window

    La línea a es evaluado en la fase inicial de ejecución global del contexto.

  2. ¿Cuál es el valor de this en la línea B cuando obj.staticFunction() se ejecuta? ¿Por qué?

    <script type="text/javascript">
    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        // Line B
    }
    
    obj.staticFunction = myFun;
    
    obj.staticFunction();
    </script>
    

    obj

    Cuando se llama a una función de un objeto, ThisBinding se establece en el objeto.

  3. ¿Cuál es el valor de this en la línea C? ¿Por qué?

    <script type="text/javascript">
    var obj = {
        myMethod : function () {
            // Line C
        }
    };
    var myFun = obj.myMethod;
    myFun();
    </script>
    

    window

    En este ejemplo, el intérprete de JavaScript introduce el código de la función, sino porque myFun/obj.myMethod no se llama en un objeto, ThisBinding se establece en window.

    Esto es diferente de Python, en la que el acceso a un método (obj.myMethod) crea un método vinculado objeto.

  4. ¿Cuál es el valor de this en la línea D? ¿Por qué?

    <script type="text/javascript">
    function myFun() {
        // Line D
    }
    var obj = {
        myMethod : function () {
            eval("myFun()");
        }
    };
    obj.myMethod();
    </script>
    

    window

    Este fue un proceso difícil. Cuando la evaluación de la eval código, this es obj. Sin embargo, en la eval código, myFun no se llama a un objeto, de manera ThisBinding se establece en window de la llamada.

  5. ¿Cuál es el valor de this , en línea E?

    <script type="text/javascript">
    function myFun() {
        // Line E
    }
    var obj = {
        someData: "a string"
    };
    myFun.call(obj);
    </script>
    

    obj

    La línea myFun.call(obj); está invocando a la especial función integrada Function.prototype.call(), que acepta thisArg como primer argumento.

46voto

Mahesha999 Puntos 2334

Esta respuesta es una réplica de mi post. Usted puede encontrar el correspondiente JSFiddles en la página de entrada.


La this de palabras clave se comporta de forma diferente en JavaScript en comparación con otros idiomas. En lenguajes Orientados a Objetos, el this de palabras clave se refiere a la instancia actual de la clase. En JavaScript, el valor de this está determinada principalmente por el contexto de invocación de la función (context.function()) y en donde se llama.

1. Cuando se utiliza en el contexto global

Cuando se utiliza this en el contexto global, es obligado a objeto global (window en navegador)

document.write(this);  //[object Window]

Cuando se utiliza this dentro de una función definida en el contexto mundial, this todavía está enlazado a objeto global ya que la función es un método de contexto global.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Anterior f1 es de hecho un método de objeto global. Por lo tanto, podemos llamar también en window objeto de la siguiente manera:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Cuando se usa en el método de objeto

Cuando se utiliza this de palabras clave dentro de un objeto método, this está vinculado a la "inmediata", adjuntando el objeto.

var obj = {
        name: "obj",
        f: function () {
            return this + ":" + this.name;
        }
    };
document.write(obj.f());  //[object Object]:obj

Arriba he puesto la palabra inmediata en comillas dobles. Es para hacer el punto de que, si el nido el objeto dentro de otro objeto, a continuación, this está obligado a la inmediata padre.

var obj = {
        name: "obj1",
        nestedobj: {
            name:"nestedobj",
            f: function () {
                return this + ":" + this.name;
            }
        }            
    }

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Incluso si se añade la función explícitamente al objeto como un método, que aún así sigue por encima de las reglas, que es this todavía señala la inmediata objeto primario.

 var obj1 = {
 name: "obj1",
}

function returnName() {
        return this + ":" + this.name;
    }

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Cuando invoque a menos del contexto de la función

Cuando se utiliza this dentro de la función que se invoca sin ningún tipo de contexto (es decir. no en cualquier objeto), está vinculada al objeto global (window en el explorador)(incluso si la función está definida en el objeto) .

var context = "global";

var obj = {  
context: "object",
method: function () {                  
       function f() {
           var context = "function";
           return this + ":" +this.context; 
       };
       return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Tratando con funciones

Podemos tratar los puntos anteriores con las funciones. Sin embargo, hay algunas diferencias.

  • Por encima añadimos que los miembros de los objetos utilizando la notación literal de objeto. Podemos agregar que los miembros de las funciones mediante el uso de this. para especificar ellos.
  • Objeto literal de la notación, se crea una instancia de objeto que se pueden utilizar inmediatamente. Con la función necesitamos primero crear su instancia mediante new operador.
  • También en un objeto literal enfoque, podemos agregar explícitamente que los miembros ya definidos objeto utilizando el operador punto. Esto se añade a la instancia específica solamente. Sin embargo, he añadido la variable de la función prototipo para que se refleja en todas las instancias de la función.

A continuación he probado todas las cosas que hicimos con el Objeto y this por encima, pero por primera función de creación en lugar de directamente de la escritura de un objeto.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Cuando se utiliza dentro de la función constructora.

Cuando se utiliza la función como un constructor (que es cuando se llama con new de palabras clave), this dentro de la función de los puntos en el cuerpo para el nuevo objeto que está siendo construido.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Cuando se utiliza dentro de la función definida en la cadena de prototipos

Si el método es un objeto prototipo de la cadena, this dentro de este método se refiere al objeto de que el método era llamado, como si el método fue definido en el objeto.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Dentro de la llamada(), apply() y atan() funciones

  • Todos estos métodos están definidos en Function.prototype.
  • Estos métodos permite escribir una función una vez y invocarlo en un contexto diferente. En otras palabras, se permite especificar el valor de this que va a ser utilizado mientras se ejecuta la función. También se tienen los parámetros que se pasan a la función original cuando se la invoca.
  • fun.apply(obj1 [, argsArray]) Sets obj1 como el valor de this dentro fun() y llamadas fun() pasando de los elementos de argsArray como sus argumentos.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Conjuntos obj1 como el valor de this dentro fun() y llamadas fun() que pasa arg1, arg2, arg3, ... como sus argumentos.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Devuelve la referencia a la función fun con this dentro de diversión enlazado obj1 y los parámetros de fun vinculado a los parámetros especificados arg1, arg2, arg3,....
  • Por ahora la diferencia entre los apply, call y bind debe de haber vuelto evidente. apply permite especificar los argumentos de la función como de la matriz como objeto, es decir. un objeto con un numéricos length de la propiedad y el correspondiente número entero no negativo de las propiedades. Mientras que call permite especificar los argumentos de la función directamente. Tanto apply y call inmediatamente invoca la función en el contexto específico y con los argumentos especificados. Por otro lado, bind simplemente devuelve la función obligado a los especificados this y el valor de los argumentos. Podemos capturar la referencia a este devueltos por la función de asignar a una variable y después nos puede llamar en cualquier momento.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this dentro de los controladores de eventos

  • Cuando se asigna la función directamente a los controladores de eventos de un elemento, el uso de this directamente dentro de la gestión de eventos de función se refiere al elemento correspondiente. Directo de la función de asignación se puede hacer utilizando addeventListener método o a través de la tradicional evento de los métodos de registro como onclick.
  • Del mismo modo, cuando se utiliza this directamente en el interior de la propiedad de evento (como <button onclick="...this..." >) del elemento, se refiere al elemento.
  • Sin embargo el uso de this indirectamente a través de otra función llamada dentro de la gestión de eventos de función o propiedad de evento se resuelve en el objeto global window.
  • El mismo comportamiento anterior se logra cuando asignamos una función al controlador de eventos con Microsoft Registro de Sucesos del método del modelo attachEvent. En lugar de asignar la función al controlador de eventos (y por lo tanto, haciendo que el método de función del elemento), se llama a la función en el evento (que efectivamente se pongan en contexto global).

Yo recomiendo mejor probar esto en JSFiddle.

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

27voto

arunjitsingh Puntos 1315

"esto" es todo sobre el alcance. Cada función tiene su propio ámbito, y puesto que todo en JS es un objeto, incluso una función puede almacenar algunos valores en sí mismo el uso de "this". La programación orientada a objetos 101 enseña que "esto" es sólo aplicable a las instancias de un objeto. Por lo tanto, cada vez se ejecuta una función, una nueva "instancia" de que la función tiene un nuevo significado de "esto".

La mayoría de las personas se confunden cuando se intentan utilizar "este" en el interior de anónimo el cierre de funciones como:

(function(value) {
 this.value = valor;
$('.some-elementos').each(function(elt){
 elt.innerHTML = this.value; / / ¡oh oh!! posiblemente no definido
});
})(2);

Así que aquí, en el interior de cada uno ()", este" no es el "valor" que se espera (a partir de

this.value = valor;
por encima de él). Así, para obtener más de esto (sin juego de palabras) problema, los desarrolladores pueden:
(function(value) {
 var auto = this; // cambio pequeño
 self.value = valor;
$('.some-elementos').each(function(elt){
 elt.innerHTML = self.value; // ufff!! == 2 
});
})(2);

Pruébalo, te vas a empezar a gustar este patrón de programación

2voto

tathagata Puntos 394

Es difícil conseguir una buena comprensión de la JS, o escribir más que nada trivial en él, si no lo entiendes bien. Usted simplemente no puede permitirse un chapuzón rápido :) Creo que la mejor manera de empezar con JS es primero ver estas lecciones en vídeo por Douglas Crockford - http://yuiblog.com/crockford/, que cubre esto y aquello y todo lo demás acerca de JS.

1voto

blockhead Puntos 4654

Todas las funciones en javascript tiene un alcance. Ese ámbito que sea, se hace referencia a "esto". Usted puede cambiar ese ámbito haciendo func.call o func.apply.

Por defecto, y lo que confunde la mayoría de los principiantes, cuando una devolución de llamada se llama después de que un evento se provoca en un elemento DOM, el alcance de la función es el elemento DOM.

jQuery hace que este trivial para cambiar con jQuery.proxy.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X