La palabra clave de JavaScript `this` + 5 reglas de enlace de teclas explicadas para principiantes de JS

La thispalabra clave de JavaScript es uno de los aspectos más difíciles de comprender del lenguaje. Pero es de vital importancia para escribir código JavaScript más avanzado.

En JavaScript, la thispalabra clave nos permite:

  • Reutilizar funciones en diferentes contextos, y
  • Identifique en qué objeto centrarse cuando se invoca un método.

Cuando se trata de this, la pregunta importante es dónde se invoca la función. Porque no sabemos qué hay en la thispalabra clave hasta que se invoca la función.

El uso de thisse puede clasificar en cinco bindingaspectos diferentes . En este artículo, aprenderemos sobre los cinco aspectos con ejemplos.

Primero, ¿qué es la vinculación?

En JavaScript, a Lexical Environmentes donde se escribe físicamente su código. En el siguiente ejemplo, el nombre de la variable está lexicallydentro de la función sayName().

function sayName() { let name = 'someName'; console.log('The name is, ', name); }

An se Execution Contextrefiere al código que se está ejecutando actualmente y todo lo demás que ayuda a ejecutarlo. Puede haber muchos entornos léxicos disponibles, pero el que se está ejecutando actualmente lo gestiona el contexto de ejecución .

Cada uno de los contextos de ejecución contiene un Environment Record. Bindingen JavaScript significa registrar el identificador (variable y nombre de función) en un registro de entorno específico.

Nota: Bindingayuda a asociar el identificador (variable y nombre de función) con la thispalabra clave para un execution context.

No se preocupe si le resulta un poco difícil de entender ahora. Obtendrá una mejor comprensión a medida que avancemos.

Regla n. ° 1: cómo funciona el enlace implícito de JavaScript

El enlace implícito cubre la mayoría de los casos de uso para tratar con la thispalabra clave.

En el enlace implícito, debe verificar lo que está a la izquierda del operador punto (.) Adyacente a una función en el momento de la invocación. Esto determina a qué thisse vincula.

Veamos un ejemplo para entenderlo mejor.

let user = { name: 'Tapas', address: 'freecodecamp', getName: function() { console.log(this.name); } }; user.getName();

Aquí thisestá vinculado al objeto de usuario. Sabemos esto porque, a la izquierda del operador de punto (.) Adyacente a la función getName(), vemos el userobjeto. Así this.nameque va a registrar Tapas en la consola.

Veamos otro ejemplo para comprender mejor este concepto:

function decorateLogName(obj) { obj.logName = function() { console.log(this.name); } }; let tom = { name: 'Tom', age: 7 }; let jerry = { name: 'jerry', age: 3 }; decorateLogName(tom); decorateLogName(jerry); tom.logName(); jerry.logName();

En este ejemplo, tenemos dos objetos tomy jerry. Hemos decorado (mejorado) estos objetos adjuntando un método llamado logName().

Observe que cuando invocamos tom.logName(), el tomobjeto está a la izquierda del operador de punto (.) Adyacente a la función logName(). Entonces thisestá vinculado al tomobjeto y registra el valor tom ( this.namees igual a tom aquí). Lo mismo se aplica cuando jerry.logName()se invoca.

Regla n. ° 2: cómo funciona el enlace explícito de JavaScript

Hemos visto que JavaScript crea un entorno para ejecutar el código que escribimos. Se encarga de la creación de memoria para variables, funciones, objetos, etc. en la fase de creación . Finalmente ejecuta el código en la fase de ejecución . Este entorno especial se llama Execution Context.

Puede haber muchos entornos de este tipo (contextos de ejecución) en una aplicación JavaScript. Cada contexto de ejecución opera independientemente de los demás.

Pero a veces, es posible que deseemos usar cosas de un contexto de ejecución en otro. Ahí es donde entra en juego la vinculación explícita.

En el enlace explícito, podemos llamar a una función con un objeto cuando la función está fuera del contexto de ejecución del objeto.

Hay tres métodos muy especiales call(), apply()y bind()que nos ayudan a lograr un enlace explícito.

Cómo funciona el call()método JavaScript

Con el call()método, el contexto con el que se debe llamar a la función se pasará como parámetro al call(). Veamos cómo funciona con un ejemplo:

let getName = function() { console.log(this.name); } let user = { name: 'Tapas', address: 'Freecodecamp' }; getName.call(user);

Aquí, el call()método se invoca en una función llamada getName(). La getName()función solo registra this.name. ¿Pero qué hay thisaquí? Eso se determina por lo que se ha pasado al call()método.

Aquí, thisse vinculará al objeto de usuario porque hemos pasado el usuario como parámetro al call()método. Por this.namelo tanto, debe registrar el valor de la propiedad de nombre del objeto de usuario, es decir, Tapas .

In the above example, we have passed just one argument to call(). But we can also pass multiple arguments to call(), like this:

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; getName.call(user, hobbies[0], hobbies[1]);

Here we have passed multiple arguments to the call() method. The first argument must be the object context with which the function has to be invoked. Other parameters could just be values to use.

Here I am passing Swimming and Blogging as two parameters to the getName() function.

Did you notice a pain point here? In case of a call(), the arguments need to be passed one by one – which is not a smart way of doing things! That's where our next method, apply(), comes into the picture.

How the JavaScript apply() Method Works

This hectic way of passing arguments to the call() method can be solved by another alternate method called apply(). It is exactly the same as call() but allows you to pass the arguments more conveniently. Have a look:

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; getName.apply(user, hobbies);

Here we are able to pass an array of arguments, which is much more convenient than passing them one by one.

Tip: When you only have one value argument or no value arguments to pass, use call(). When you have multiple value arguments to pass, use apply().

How The JavaScript bind() Method Works

The bind() method is similar to the call() method but with one difference. Unlike the call() method of calling the function directly, bind() returns a brand new function and we can invoke that instead.

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; let newFn = getName.bind(user, hobbies[0], hobbies[1]); newFn();

Here the getName.bind() doesn't invoke the function getName()directly. It returns a new function, newFn and we can invoke it as newFn().

Rule #3: The JavaScript new Binding

A new keyword is used to create an object from the constructor function.

let Cartoon = function(name, animal) { this.name = name; this.animal = animal; this.log = function() { console.log(this.name + ' is a ' + this.animal); } };

You can create objects using the new keyword  like this:

 let tom = new Cartoon('Tom', 'Cat'); let jerry = new Cartoon('Jerry', 'Mouse');

The constructor function's new binding rule states that, when a function is invoked with the new keyword, the this keyword inside the function binds to the new object being constructed.

Sounds complex? Ok, let's break it down. Take this line,

let tom = new Cartoon('Tom', 'Cat');

Here the function Cartoon is invoked with the new keyword. So this will be bound to the new object being created here, which is tom.

Rule #4: JavaScript Global Object Binding

What do you think will be the output of the code below? What is this binding to here?

let sayName = function(name) { console.log(this.name); }; window.name = 'Tapas'; sayName();

If the this keyword is not resolved with any of the bindings, implicit, explicit or new, then the this is bound to the window(global) object.

There is one exception though. JavaScript strict mode does not allow this default binding.

"use strict"; function myFunction() { return this; }

In the above case, this is undefined.

Rule #5: HTML Event Element Binding in JavaScript

In HTML event handlers, this binds to the HTML elements that receive the event.

Click Me!

The is the output log in the console when you click on the button:

"Click Me!"

You can change the button style using the this keyword, like this:

Click Me!

But be mindful when you call a function on the button click and use this inside that function.

Click Me!

and the JavaScript:

function changeColor() { this.style.color='teal'; }

The above code won't work as expected. As we have seen in the Rule 4, here this will be bound to the global object (in the 'non-strict' mode) where there is no style object to set the color.

In Summary

To summarize,

  • In the case of implicit binding, this binds to the object to the left of the dot(.) operator.
  • In the case of explicit binding, we can call a function with an object when the function is outside of the execution context of the object. The methods call(), apply(), and bind() play a big role here.
  • When a function is invoked with the new keyword, the this keyword inside the function binds to the new object being constructed.
  • When the this keyword is not resolved with any of the bindings, implicit, explicit or new, then this is bound to the window(global) object. In JavaScript's strict mode, this will be undefined.
  • In HTML event handlers, this binds to the HTML elements that receive the event.

There is one more case where this behaves differently, such as with ES6 arrow functions. We will take a look at that in a future article.

I hope you found this article insightful. You may also like,

  • JavaScript Hoisting Internals
  • Understanding JavaScript Execution Context like never before
  • JavaScript Scope Fundamentals with Tom and Jerry
  • Understanding JavaScript Closure with example

If this article was useful, please share it so others can read it as well. You can @ me on Twitter (@tapasadhikary) with comments, or feel free to follow me.