Desmistificando o JavaScript desta palavra-chave

Resumo : neste tutorial, você aprenderá sobre o thisvalor do JavaScript e o compreenderá claramente em vários contextos.

Se você trabalha com outras linguagens de programação, como Java, C# ou PHP , já está familiarizado com a thispalavra-chave.

Nessas linguagens, a  thispalavra-chave representa a instância atual da classe e só é relevante dentro da classe.

JavaScript também possui thispalavra-chave. No entanto, a thispalavra-chave em JavaScript se comporta de maneira diferente de outras linguagens de programação.

Em JavaScript, você pode usar a  thispalavra-chave nos contextos global e de função . Além disso, o comportamento da   thispalavra-chave muda entre os modos estrito e não estrito.

Qual é esta palavra-chave

Em geral, thisfaz referência ao objeto do qual a função é uma propriedade. Em outras palavras, faz thisreferência ao objeto que está chamando a função no momento.

Suponha que você tenha um objeto counterque possua um método next(). Ao chamar o next()método, você pode acessar o thisobjeto.

let counter = {
  count: 0,
  next: function () {
    return ++this.count;
  },
};

counter.next();Linguagem de código:  JavaScript  ( javascript )

Dentro da next()função, faz thisreferência ao counterobjeto. Veja a seguinte chamada de método:

counter.next();Linguagem de código:  CSS  ( css )

A next()é uma função que é propriedade do counterobjeto. Portanto, dentro da next()função, faz thisreferência ao counterobjeto.

Contexto global

No contexto global, faz thisreferência ao objeto global , que é o windowobjeto no navegador da web ou globalobjeto no Node.js.

Esse comportamento é consistente nos modos estrito e não estrito. Aqui está a saída no navegador da web:

console.log(this === window); // trueLinguagem de código:  JavaScript  ( javascript )

Se você atribuir uma propriedade ao thisobjeto no contexto global, o JavaScript adicionará a propriedade ao objeto global conforme mostrado no exemplo a seguir:

this.color= 'Red';
console.log(window.color); // 'Red'Linguagem de código:  JavaScript  ( javascript )

Contexto da função

Em JavaScript, você pode chamar uma função das seguintes maneiras:

  • Invocação de função
  • Invocação de método
  • Invocação do construtor
  • Invocação indireta

Cada invocação de função define seu próprio contexto. Portanto, o thisse comporta de maneira diferente.

1) Invocação de função simples

No modo não estrito, faz thisreferência ao objeto global quando a função é chamada da seguinte forma:

function show() {
   console.log(this === window); // true
}

show();Linguagem de código:  JavaScript  ( javascript )

Quando você chama a show()função, ela thisfaz referência ao objeto global , que está no windownavegador da web e globalno Node.js.

Chamar a show()função é o mesmo que:

window.show();Linguagem de código:  JavaScript  ( javascript )

No modo estrito, o JavaScript define o thisinterior de uma função como undefined. Por exemplo:

"use strict";

function show() {
    console.log(this === undefined);
}

show();Linguagem de código:  JavaScript  ( javascript )

Para ativar o modo estrito, você usa a diretiva "use strict"no início do arquivo JavaScript. Se você deseja aplicar o modo estrito apenas a uma função específica, coloque-o no topo do corpo da função.

Observe que o modo estrito está disponível desde ECMAScript 5.1. O strictmodo se aplica a funções e funções aninhadas. Por exemplo:

function show() {
    "use strict";
    console.log(this === undefined); // true

    function display() {
        console.log(this === undefined); // true
    }
    display();
}

show();Linguagem de código:  JavaScript  ( javascript )

Saída:

true
trueLinguagem de código:  JavaScript  ( javascript )

Na display()função interna, thistambém definido undefinedcomo mostrado no console.

2) Invocação de método

Quando você chama um método de um objeto, o JavaScript define thiso objeto que possui o método. Veja o seguinte carobjeto:

let car = {
    brand: 'Honda',
    getBrand: function () {
        return this.brand;
    }
}

console.log(car.getBrand()); // HondaLinguagem de código:  JavaScript  ( javascript )

Neste exemplo, o thisobjeto no getBrand()método faz referência ao carobjeto.

Como um método é uma propriedade de um objeto que é um valor, você pode armazená-lo em uma variável.

let brand = car.getBrand;Linguagem de código:  JavaScript  ( javascript )

E então chame o método através da variável

console.log(brand()); // undefinedLinguagem de código:  JavaScript  ( javascript )

Você obtém undefinedem vez de "Honda"porque quando você chama um método sem especificar seu objeto, o JavaScript define thiso objeto global no modo não estrito e undefinedno modo estrito.

Para corrigir esse problema, você usa o bind()método do Function.prototypeobjeto. O bind()método cria uma nova função cuja thispalavra-chave é definida com um valor especificado.

let brand = car.getBrand.bind(car);
console.log(brand()); // Honda
Linguagem de código:  JavaScript  ( javascript )

Neste exemplo, quando você chama o brand()método, a thispalavra-chave está vinculada ao carobjeto. Por exemplo:

let car = {
    brand: 'Honda',
    getBrand: function () {
        return this.brand;
    }
}

let bike = {
    brand: 'Harley Davidson'
}

let brand = car.getBrand.bind(bike);
console.log(brand());Linguagem de código:  JavaScript  ( javascript )

Saída:

Harley Davidson

Neste exemplo, o bind()método define the thispara o bikeobjeto, portanto, você vê o valor da brandpropriedade do bikeobjeto no console.

3) Invocação do construtor

Ao usar a newpalavra-chave para criar uma instância de um objeto de função, você usa a função como construtor.

O exemplo a seguir declara uma Carfunção e a invoca como construtor:

function Car(brand) {
    this.brand = brand;
}

Car.prototype.getBrand = function () {
    return this.brand;
}

let car = new Car('Honda');
console.log(car.getBrand());Linguagem de código:  JavaScript  ( javascript )

A expressão new Car('Honda')é uma invocação do construtor da Carfunção.

JavaScript cria um novo objeto e define thiso objeto recém-criado. Esse padrão funciona muito bem com apenas um problema potencial.

Agora, você pode invocar Car()como uma função ou como um construtor. Se você omitir a newpalavra-chave da seguinte forma:

var bmw = Car('BMW');
console.log(bmw.brand);
// => TypeError: Cannot read property 'brand' of undefinedLinguagem de código:  JavaScript  ( javascript )

Desde o thisvalor nos Car()conjuntos até o objeto global, o bmw.brandretorno é undefined.

Para garantir que a Car()função seja sempre invocada usando a invocação do construtor, adicione uma verificação no início da Car()função da seguinte maneira:

function Car(brand) {
    if (!(this instanceof Car)) {
        throw Error('Must use the new operator to call the function');
    }
    this.brand = brand;
}Linguagem de código:  JavaScript  ( javascript )

ES6 introduziu uma metapropriedade chamada new.targetque permite detectar se uma função é invocada como uma invocação simples ou como um construtor.

Você pode modificar a Car()função que usa a new.targetmetapropriedade da seguinte maneira:

function Car(brand) {
    if (!new.target) {
        throw Error('Must use the new operator to call the function');
    }
    this.brand = brand;
}Linguagem de código:  JavaScript  ( javascript )

4) Invocação Indireta

Em JavaScript, as funções são cidadãs de primeira classe . Em outras palavras, funções são objetos, que são instâncias do tipo Function .

O Functiontipo possui dois métodos: call()e apply(). Esses métodos permitem definir o thisvalor ao chamar uma função. Por exemplo:

function getBrand(prefix) {
    console.log(prefix + this.brand);
}

let honda = {
    brand: 'Honda'
};
let audi = {
    brand: 'Audi'
};

getBrand.call(honda, "It's a ");
getBrand.call(audi, "It's an ");Linguagem de código:  JavaScript  ( javascript )

Saída:

It's a Honda
It's an AudiLinguagem de código:  PHP  ( php )

Neste exemplo, chamamos a getBrand()função indiretamente usando o call()método da getBrandfunção. Passamos hondae   audiobject como primeiro argumento do call()método, portanto, obtivemos a marca correspondente em cada chamada.

O apply()método é semelhante ao call()método, exceto que seu segundo argumento é uma matriz de argumentos.

getBrand.apply(honda, ["It's a "]); // "It's a Honda"
getBrand.apply(audi, ["It's an "]); // "It's a Audi"Linguagem de código:  JavaScript  ( javascript )

Funções de seta

ES6 introduziu um novo conceito chamado função de seta . Nas funções de seta, o JavaScript define o thislexicamente.

Isso significa que a função de seta não cria seu próprio contexto de execução , mas herda o this da função externa onde a função de seta está definida. Veja o exemplo a seguir:

let getThis = () => this;
console.log(getThis() === window); // trueLinguagem de código:  JavaScript  ( javascript )

Neste exemplo, o thisvalor é definido para o objeto global, ou seja, windowno navegador da web.

Como uma função de seta não cria seu próprio contexto de execução, definir um método usando uma função de seta causará um problema. Por exemplo:

function Car() {
  this.speed = 120;
}

Car.prototype.getSpeed = () => {
  return this.speed;
};

var car = new Car();
console.log(car.getSpeed()); // 👉 undefinedLinguagem de código:  JavaScript  ( javascript )

Dentro do getSpeed()método, o thisvalor faz referência ao objeto global, não ao Carobjeto, mas o objeto global não possui uma propriedade chamada velocidade. Portanto, o this.speedno getSpeed()método retorna undefined.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *