¿Qué significa new this() en Javascript?

Que Javascript es un lenguaje con un diseño sumamente confuso un tanto peculiar es algo que a estas alturas ya no se le escapa a nadie. Todos conocemos los típicos ejemplos de comportamientos impredecibles cuando se empiezan a mezclar las reglas de coerción de tipos con operadores como +, == o ===.

Aun así, si algo tengo que reconocerle a Javascript es que siempre puedes encontrar algo nuevo que te sorprenda. Lo último ha sido ver código parecido a éste:

const x = new this();

Si viendo ese código ya tienes clarísimo lo que hace, te puedes ahorrar el resto del post. Por el contrario, si a simple vista te resulta tan extraño como a mi, vamos a intentar descifrarlo poco a poco.

this en Javascript

Éste debe de ser el único blog que queda en internet sin hablar de esto, y tampoco quiero profundizar mucho ahora, pero para entender lo que significa new this() primero es necesario recordar cómo funciona this en Javascript.

En lenguajes como C# o Java, this hace referencia a la instancia actual de la clase sobre la que se está ejecutando un método. El valor de this queda fijado por la clase en que está definido el método y siempre será una instancia de esa clase (o de una clase derivada de ella).

En el caso de Javascript, this hace referencia al objeto sobre el que se ejecuta una función, pero al no haber un concepto de clase comparable al de C#/Java (y no, la sintaxis class no significa lo mismo), la cosa cambia bastante porque podemos hacer que una función esté enlazada a diferentes objetos:

function sayHello() {
  console.log('Hi, ' + this.name);
}

const m = { name: 'Marcos', sayHello }
m.sayHello() // Hi, Marcos

const j = { name: 'Juan', sayHi: sayHello }
j.sayHi(), // Hi, Juan

Podemos crear una función, asignarla a distintos objetos, y el valor de this al ejecutar la función dependerá del objeto que la contenga en cada momento. Esto no es del todo cierto y se puede controlar mejor con las funciones bind, call, apply, o usando funciones arrow, pero ahora eso nos importa relativamente poco.

La idea con la que te tienes que quedar es que this no tiene nada que ver con clases, sino que referencia el objeto sobre el que se ejecuta una función, que puede coincidir o no con el objeto en el que se definió.

Funciones y objetos en Javascript

En Javascript podemos crear objetos mediante la sintaxis para objetos literales, como veíamos en el ejemplo anterior, o usando funciones constructoras. Y poco más. La sintaxis «nueva» para definir clases es, en realidad, azucar sintáctico sobre las funciones constructoras, pero se puede traducir a ellas. De hecho, cualquier función en Javascript se puede usar como función constructora si la invocamos con new (aunque a veces eso tenga poco sentido):

function sum(a, b) {
  return a + b;
}

const x = new sum(1, 2);
x instanceof sum // true

Además, las funciones en Javascript también son objetos, por lo que pueden tener sus propiedades adicionales y a las que les podemos enlazar otras funciones:

function sum(a, b) {
  return (a + b) * sum.factor;
}
sum.factor = 2;
sum.incFactor = function() { sum.factor ++; }

sum.incFactor();
sum(1, 2) === 9; // true (1 + 2) * 3

Atando cabos

Pensando en lo que acabamos de ver (y que en el fondo ya sabíamos) sobre this y las funciones como objetos en Javascript, es fácil razonar lo que hace ese extraño new this() que veíamos al principio del post.

Imagina este código:

function Person() {
}

Person.create = function() {
  return new this();
}

const p = Person.create();
p instanceof Person; // true

Si entendemos la función como un objeto y le asociamos una propiedad que es otra función, en esa otra función this se referirá a la propia función y, como hemos visto, cualquier función podemos usarla como una función constructora.

Podemos hacer una traducción aproximada del código anterior a sintaxis de clases y tendríamos el mismo resultado:

class Person {
  static create() {
    return new this();
  }
}

const p = Person.create();
p instanceof Person; // true

Esto funciona incluso con relaciones de herencia, permitiendo tener métodos estáticos cuyo comportamiento cambia dependiendo del punto de la jerarquía desde el que se invoquen:

class Employee extends Person {
}

const e = Employee.create();
e instanceof Employee; // true
e instanceof Person; // true

Dependiendo de si invocamos el «método estático» desde el objeto que representa a la clase base o a la clase derivada, el valor de this cambiará y crearemos un tipo de objeto u otro.

Y todo esto, ¿para qué sirve?

Pues la verdad es que no tengo ni idea, más allá de que resulte curioso para pasar el rato. Quizá en algún escenario en el que tuvieras que simular factorías para una jerarquía de «clases» pueda tener algún uso, pero estoy casi seguro de que siempre vas a poder encontrar un diseño más sencillo de seguir.

Conclusión

Javascript es un lenguaje que tiene muchas pegas, pero la flexibilidad que ofrece hace que en ocasiones puedes encontrar planteamientos interesantes desde el punto de vista de metaprogramación. Al manejar muy pocos tipos de primitivas y tener una frontera muy difusa entre ellas (como el caso de las funciones que también son objetos) puedes hacer muchas guarrerías cosas que son complicadas en otros lenguajes de programación.

A veces incluso pueden resultar útiles, como el caso de crear nuevas clases dinámicamente desde funciones, como vimos al hablar de los componentes de orden superior en ReactJS.

Lo importante, con Javascript o con cualquier lenguaje, es intentar entender cómo funcionan las cosas que utilizamos y no quedarnos con la sensación de ser los más listos sólo porque sabemos tirar un par de pantallas con el framework de turno.


3 comentarios en “¿Qué significa new this() en Javascript?

  1. > Y todo esto, ¿para qué sirve?

    No sabiendo dónde lo has visto se hace más difícil contestar, pero… Hoy en día realmente tiene poco uso; o debería tenerlo.

    En el pasado ( mira este ejemplo de 2008 -preES6-: https://johnresig.com/blog/simple-javascript-inheritance/ ), hacer new this() era «relativamente» frecuente/útil, para producir diferentes esquemas de herencia. Si recuerdas en esa época era lo que se llevaba. No eras nadie en JS si no te inventabas una forma de hacer «herencia y clases» para tu librería. new this() te ofrece una forma de poder «instanciar» algo que no sabes qué es en tiempo de escritura (es decir, de forma genérica). En esa época, como decía, un puñado de librerías que intentaban ofrecer algún tipo de jerarquía de componentes (y/o formas de crear esas jerarquías), solían hacer esto.

    Pero esto, hoy por hoy -en los días de ES2015+-, es algo mucho menos habitual y generalmente desaconsejado. Es más lógico usar la «nueva» sintaxis de clases y quedarse con eso. Como dices tú, casi seguro que cualquier uso que se te ocurra se puede hacer de otro modo más sencillo.

    Si algún día llegan a ponerse de acuerdo con el follón que hay de propuestas para slots privados, podría ocurrir que de alguna forma juntando ambas cosas se pueda llegar a algún resultado útil -en cuanto a manejar y controlar la instanciación- y con un esquema no demasiado complejo/confuso.

    En cualquier caso, «new this()» realmente no es algo de lo que vayamos a hacer uso de forma habitual -seguramente ni siquiera de forma excepcional- en la mayoría de cosas que hagamos.

Comentarios cerrados.