programa historia funciona evolucion definicion como caracteristicas actual javascript language-features language-design

javascript - historia - ¿Cómo funciona la palabra clave “this” dentro de una función?



javascript wikipedia (5)

¿Es este comportamiento definido? ¿Es seguro para todos los navegadores?

Sí. Y si.

¿Hay algún razonamiento subyacente por qué es la forma en que es ...

El significado de this es bastante simple de deducir:

  1. Si this se usa dentro de una función constructora, y la función se invocó con la new palabra clave, se refiere al objeto que se creará. this continuará significando el objeto incluso en métodos públicos.
  2. Si se usa en cualquier otro lugar, incluidas las funciones protegidas anidadas, se refiere al ámbito global (que en el caso del navegador es el objeto de la ventana).

El segundo caso es obviamente un defecto de diseño, pero es bastante fácil solucionarlo utilizando cierres.

Acabo de encontrar una situación interesante en JavaScript. Tengo una clase con un método que define varios objetos usando notación de objeto literal. Dentro de esos objetos, se está utilizando el puntero de this . Del comportamiento del programa, deduje que this puntero se refiere a la clase en la que se invocó el método y no al objeto creado por el literal.

Esto parece arbitrario, aunque es la forma en que esperaría que funcionara. ¿Es este comportamiento definido? ¿Es seguro para todos los navegadores? ¿Hay algún razonamiento que explique por qué es así como está más allá de "la especificación así lo dice" (por ejemplo, es una consecuencia de una decisión / filosofía de diseño más amplia)? Ejemplo de código al revés:

// inside class definition, itself an object literal, we have this function: onRender: function() { this.menuItems = this.menuItems.concat([ { text: ''Group by Module'', rptletdiv: this }, { text: ''Group by Status'', rptletdiv: this }]); // etc }


Funciones de llamadas

Las funciones son solo un tipo de objeto.

Todos los objetos de función tienen métodos de call y de apply que ejecutan el objeto de función al que se llama.

Cuando se llama, el primer argumento de estos métodos especifica el objeto al que hará referencia this palabra clave durante la ejecución de la función: si es null o undefined , el objeto global, la window , se usa para this .

Así, llamando a una función ...

whereAmI = "window"; function foo() { return "this is " + this.whereAmI + " with " + arguments.length + " + arguments"; }

... con paréntesis - foo() - es equivalente a foo.call(undefined) o foo.apply(undefined) , que en realidad es lo mismo que foo.call(window) o foo.apply(window) .

>>> foo() "this is window with 0 arguments" >>> foo.call() "this is window with 0 arguments"

Los argumentos adicionales a los que se call se pasan como argumentos a la llamada a la función, mientras que un solo argumento adicional a apply puede especificar los argumentos para la llamada a la función como un objeto similar a una matriz.

Por lo tanto, foo(1, 2, 3) es equivalente a foo.call(null, 1, 2, 3) o foo.apply(null, [1, 2, 3]) .

>>> foo(1, 2, 3) "this is window with 3 arguments" >>> foo.apply(null, [1, 2, 3]) "this is window with 3 arguments"

Si una función es una propiedad de un objeto ...

var obj = { whereAmI: "obj", foo: foo };

... acceder a una referencia a la Función a través del objeto y llamarla con paréntesis - obj.foo() - es equivalente a foo.call(obj) o foo.apply(obj) .

Sin embargo, las funciones mantenidas como propiedades de objetos no están "vinculadas" a esos objetos. Como puede ver en la definición de obj anterior, ya que las Funciones son solo un tipo de Objeto, pueden ser referenciadas (y por lo tanto pueden pasarse por referencia a una llamada de Función o devolverse por referencia de una llamada de Función). Cuando se pasa una referencia a una función, no se lleva consigo información adicional sobre desde dónde se pasó, por lo que sucede lo siguiente:

>>> baz = obj.foo; >>> baz(); "this is window with 0 arguments"

La llamada a nuestra referencia de función, baz , no proporciona ningún contexto para la llamada, por lo que efectivamente es lo mismo que baz.call(undefined) , así que this termina en la window referencia. Si queremos que baz sepa que pertenece a obj , debemos proporcionar de alguna manera esa información cuando se llama a baz , que es donde el primer argumento para call o apply y los cierres entran en juego.

Cadenas de alcance

function bind(func, context) { return function() { func.apply(context, arguments); }; }

Cuando se ejecuta una función, crea un nuevo ámbito y tiene una referencia a cualquier ámbito adjunto. Cuando la función anónima se crea en el ejemplo anterior, tiene una referencia al ámbito en el que se creó, que es el alcance de bind . Esto se conoce como un "cierre".

[global scope (window)] - whereAmI, foo, obj, baz | [bind scope] - func, context | [anonymous scope]

Cuando intenta acceder a una variable, esta "cadena de alcance" se recorre para encontrar una variable con el nombre dado: si el alcance actual no contiene la variable, mira el siguiente alcance de la cadena, y así sucesivamente hasta llegar a El alcance global. Cuando se devuelve la función anónima y el bind termina de ejecutarse, la función anónima todavía tiene una referencia al alcance del bind , por lo que el alcance del bind no "desaparece".

Teniendo en cuenta todo lo anterior, ahora debería ser capaz de comprender cómo funciona el alcance en el siguiente ejemplo, y por qué la técnica para pasar una función alrededor de "predefinido" con un valor particular de this tendrá cuando se la llame funciona:

>>> baz = bind(obj.foo, obj); >>> baz(1, 2); "this is obj with 2 arguments"


Canibalizado de otra publicación mía, aquí hay más de lo que siempre quisiste saber sobre esto .

Antes de comenzar, esto es lo más importante que debes tener en cuenta sobre Javascript y repetirte cuando no tenga sentido. Javascript no tiene clases (la class ES6 es azúcar sintáctica ). Si algo parece una clase, es un truco inteligente. Javascript tiene objetos y funciones . (eso no es 100% preciso, las funciones son solo objetos, pero a veces puede ser útil pensar en ellos como cosas separadas)

La variable esta adjunta a las funciones. Cada vez que invoca una función, se le asigna un cierto valor, dependiendo de cómo invoque la función. Esto a menudo se llama el patrón de invocación.

Hay cuatro formas de invocar funciones en javascript. Puede invocar la función como método , como función , como constructor y con apply .

Como metodo

Un método es una función que está asociada a un objeto.

var foo = {}; foo.someMethod = function(){ alert(this); }

Cuando se invoca como método, esto se vinculará al objeto del que forma parte la función / método. En este ejemplo, esto estará vinculado a foo.

Como una función

Si tiene una función autónoma, esta variable estará vinculada al objeto "global", casi siempre el objeto de ventana en el contexto de un navegador.

var foo = function(){ alert(this); } foo();

Esto puede ser lo que te hace tropezar , pero no te sientas mal. Muchas personas consideran que esta es una mala decisión de diseño. Dado que una devolución de llamada se invoca como una función y no como un método, es por eso que está viendo lo que parece ser un comportamiento inconsistente.

Muchas personas solucionan el problema haciendo algo como, um, esto

var foo = {}; foo.someMethod = function (){ var that=this; function bar(){ alert(that); } }

Se define una variable que apunta a esto . El cierre (un tema que es propio) mantiene eso alrededor, por lo que si llama a la barra como devolución de llamada, todavía tiene una referencia.

NOTA: En el modo use strict , si se usa como función, this no está vinculado a global. (Está undefined ).

Como constructor

También puedes invocar una función como un constructor. Según la convención de nomenclatura que está usando (TestObject), esto también puede ser lo que está haciendo y es lo que lo está haciendo tropezar .

Invoca una función como Constructor con la nueva palabra clave.

function Foo(){ this.confusing = ''hell yeah''; } var myObject = new Foo();

Cuando se invoca como un constructor, se creará un nuevo Objeto, y esto se vinculará a ese objeto. Nuevamente, si tiene funciones internas y se usan como devoluciones de llamada, las invocará como funciones, y esto estará vinculado al objeto global. Usa esa var que = este truco / patrón.

Algunas personas piensan que la palabra clave constructor / nueva fue un hueso lanzado a los programadores de OOP de Java / tradicionales como una forma de crear algo similar a las clases.

Con el método de aplicación

Finalmente, cada función tiene un método (sí, las funciones son objetos en Javascript) llamado "aplicar". Aplicar le permite determinar cuál será el valor de esto y también le permite pasar una serie de argumentos. Aquí hay un ejemplo inútil.

function foo(a,b){ alert(a); alert(b); alert(this); } var args = [''ah'',''be'']; foo.apply(''omg'',args);


En este caso, el interno está vinculado al objeto global en lugar de a this variable de la función externa. Es la forma en que está diseñado el lenguaje.

Consulte "JavaScript: The Good Parts" de Douglas Crockford para obtener una buena explicación.


He encontrado un buen tutorial sobre el ECMAScript esto

Este valor es un objeto especial que está relacionado con el contexto de ejecución. Por lo tanto, puede ser nombrado como un objeto de contexto (es decir, un objeto en cuyo contexto se activa el contexto de ejecución).

Cualquier objeto puede ser usado como este valor del contexto.

a este valor es una propiedad del contexto de ejecución, pero no una propiedad del objeto variable.

Esta característica es muy importante, porque al contrario de las variables, este valor nunca participa en el proceso de resolución de identificadores. Es decir, al acceder a esto en un código, su valor se toma directamente del contexto de ejecución y sin ninguna búsqueda en la cadena de alcance. El valor de esto se determina solo una vez al entrar en el contexto.

En el contexto global, a este valor es el objeto global en sí mismo (es decir, este valor aquí es igual al objeto variable)

En el caso de un contexto de función, este valor en cada llamada de función puede ser diferente

Referencia Javascript-the-core y Chapter-3-this