O que é escopo lexical?

682

O que é uma breve introdução ao escopo lexical?

Subba Rao
fonte
89
No podcast 58, Joel incentiva perguntas como estas, pois ele quer que OO seja o lugar para respostas, mesmo que tenham sido respondidas em outros lugares. Esta é uma pergunta válida, mesmo que alguém possa colocá-la um pouco mais educada.
Ralph M. Rickenbach
5
@rahul eu entendo que é uma pergunta antiga. Mas tenho certeza que, mesmo em 2009, a SO esperava que os solicitantes enviassem algum esforço básico para resolvê-lo. Tal como está, não mostra nenhum esforço. Pode ser, é por isso que foi rebaixado por muitos?
PP
13
É possível que o consulente não é (ou não foi) fluente em Inglês, ao escrever esta pergunta
Martin
27
A pergunta é educada, ele apenas diz o que quer. Você é livre para responder. Não há necessidade de polibilidade excessivamente sensível aqui.
Markus Siebeneicher
25
Acho que perguntas como essas são ótimas porque cria conteúdo para SO. IMO, quem se importa se a pergunta não tiver esforço ... as respostas terão um ótimo conteúdo e é isso que importa neste quadro de mensagens.
precisa saber é o seguinte

Respostas:

686

Eu os entendo através de exemplos. :)

Primeiro, escopo lexical (também chamado de escopo estático ), na sintaxe do tipo C:

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

Todo nível interno pode acessar seus níveis externos.

Existe uma outra maneira, chamada de escopo dinâmico usado pela primeira implementação do Lisp , novamente em uma sintaxe do tipo C:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

Aqui você funpode acessar xem dummy1ou dummy2, ou qualquer xem qualquer função que chamar funcom xdeclarada nele.

dummy1();

imprimirá 5,

dummy2();

imprimirá 10.

O primeiro é chamado estático porque pode ser deduzido em tempo de compilação, e o segundo é chamado dinâmico porque o escopo externo é dinâmico e depende da chamada em cadeia das funções.

Acho o escopo estático mais fácil para os olhos. A maioria dos idiomas acabou por esse caminho, até o Lisp (pode fazer as duas coisas, certo?). O escopo dinâmico é como passar referências de todas as variáveis ​​para a função chamada.

Como um exemplo de por que o compilador não pode deduzir o escopo dinâmico externo de uma função, considere nosso último exemplo. Se escrevermos algo como isto:

if(/* some condition */)
    dummy1();
else
    dummy2();

A cadeia de chamadas depende de uma condição de tempo de execução. Se for verdade, a cadeia de chamadas se parece com:

dummy1 --> fun()

Se a condição for falsa:

dummy2 --> fun()

O escopo externo de funambos os casos é o chamador mais o chamador do chamador e assim por diante .

Apenas para mencionar que a linguagem C não permite funções aninhadas nem escopo dinâmico.

AraK
fonte
19
Também gostaria de destacar um tutorial muito fácil de entender que acabei de encontrar. O exemplo de Arak é bom, mas pode ser muito curto para alguém que precisa de mais exemplos (na verdade, comparando com outros idiomas ..). Dê uma olhada. É importante entender isso , pois essa palavra-chave nos levará a entender o escopo lexical. howtonode.org/what-is-this
CppLearner
9
Esta é uma boa resposta. Mas a pergunta está marcada com JavaScript. Portanto, acho que isso não deve ser marcado como a resposta aceita. Âmbito lexical especificamente em JS é diferente
Boyang
6
Resposta extremamente boa. Obrigado. @ Boyoy eu discordo. Eu não sou um codificador Lisp, mas achei o exemplo Lisp útil, pois é um exemplo de escopo dinâmico, que você não obtém no JS.
Dudewad 10/10
4
Inicialmente, pensei que o exemplo era um código C válido e fiquei confuso se havia escopo dinâmico em C. Talvez a isenção de responsabilidade no final possa ser alterada antes do exemplo de código?
Yangshun Tay
2
Ainda é uma resposta muito útil, mas acho que o @Boyang está correto. Essa resposta se refere ao 'nível', que é mais parecido com o escopo do bloco que C possui. Por padrão, o JavaScript não tem escopo no nível do bloco; portanto, dentro de um forloop é o problema típico. O escopo lexical do JavaScript é apenas no nível da função, a menos que o ES6 letou constseja usado.
icc97
274

Vamos tentar a definição mais curta possível:

O escopo léxico define como os nomes de variáveis ​​são resolvidos em funções aninhadas: as funções internas contêm o escopo das funções pai, mesmo que a função pai tenha retornado .

Isso é tudo o que existe!

Pierre Spring
fonte
21
A última parte: "mesmo se a função pai retornou" é chamada de fechamento.
Juanma Menendez
1
Entendeu o escopo e o fechamento lexical em apenas uma sentença. Obrigado!!
Masmorra
63
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

O código acima retornará "Eu sou apenas um local". Não retornará "Eu sou global". Como a função func () conta onde está originalmente definido, está no escopo da função whatismyscope.

Ele não se incomoda com o que está sendo chamado (o escopo global / mesmo dentro de outra função), é por isso que o valor do escopo global Eu sou global não será impresso.

Isso é chamado de escopo lexical, em que " funções são executadas usando a cadeia de escopo que estava em vigor quando foram definidas " - de acordo com o JavaScript Definition Guide.

O escopo léxico é um conceito muito, muito poderoso.

Espero que isto ajude..:)

kta
fonte
3
explicação muito boa, eu quero adicionar mais uma coisa, se você escrever a função func () {return this.scope;} então ele retornará "Eu sou global", use essa palavra-chave e seu escopo sofrerá alterações
Rajesh Kumar Bhawsar
41

O escopo léxico (AKA estático) refere-se à determinação do escopo de uma variável com base exclusivamente em sua posição no corpus de código textual. Uma variável sempre se refere ao seu ambiente de nível superior. É bom entendê-lo em relação ao escopo dinâmico.

Evan Meagher
fonte
41

O escopo define a área em que funções, variáveis ​​e outras estão disponíveis. A disponibilidade de uma variável, por exemplo, é definida dentro do seu contexto, digamos que a função, arquivo ou objeto em que estão definidos. Geralmente chamamos essas variáveis ​​locais.

A parte lexical significa que você pode derivar o escopo da leitura do código fonte.

O escopo léxico também é conhecido como escopo estático.

O escopo dinâmico define variáveis ​​globais que podem ser chamadas ou referenciadas de qualquer lugar após serem definidas. Às vezes, eles são chamados de variáveis ​​globais, embora as variáveis ​​globais na maioria das linguagens de programação sejam de escopo lexical. Isso significa que pode ser derivado da leitura do código que a variável está disponível neste contexto. Talvez seja necessário seguir uma cláusula de usos ou inclusões para encontrar a instância ou definição, mas o código / compilador conhece a variável nesse local.

No escopo dinâmico, por outro lado, você pesquisa primeiro a função local, depois a função que chamou a função local, depois a função que chamou essa função e assim por diante, na pilha de chamadas. "Dinâmico" refere-se à mudança, pois a pilha de chamadas pode ser diferente toda vez que uma determinada função é chamada e, portanto, a função pode atingir variáveis ​​diferentes, dependendo de onde é chamada. (veja aqui )

Para ver um exemplo interessante de escopo dinâmico, consulte aqui .

Para mais detalhes, veja aqui e aqui .

Alguns exemplos em Delphi / Object Pascal

Delphi tem escopo lexical.

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

O Delphi mais próximo do escopo dinâmico é o par de funções RegisterClass () / GetClass (). Para seu uso veja aqui .

Digamos que a hora em que RegisterClass ([TmyClass]) é chamada para registrar uma determinada classe não possa ser prevista lendo o código (é chamado em um método de clique no botão chamado pelo usuário), o código que chama GetClass ('TmyClass') será resultado ou não. A chamada para RegisterClass () não precisa estar no escopo lexical da unidade usando GetClass ();

Outra possibilidade de escopo dinâmico são os métodos anônimos (encerramentos) no Delphi 2009, pois eles conhecem as variáveis ​​de sua função de chamada. Ele não segue o caminho de chamada de lá recursivamente e, portanto, não é totalmente dinâmico.

Ralph M. Rickenbach
fonte
2
Na verdade, o privado é acessível em toda a unidade em que a classe está definida. É por isso que "Privado restrito" foi introduzido no D2006.
Marco van de Voort
2
+1 para linguagem simples (em oposição a ambos linguagem complicada e exemplos sem muita descrição)
Pops
36

Adoro as respostas totalmente independentes e independentes do idioma de pessoas como @Arak. Como essa pergunta foi marcada como JavaScript , gostaria de incluir algumas notas muito específicas para esse idioma.

Em JavaScript, nossas opções de escopo são:

  • como está (sem ajuste de escopo)
  • lexical var _this = this; function callback(){ console.log(_this); }
  • limite callback.bind(this)

Vale a pena notar, eu acho, que o JavaScript realmente não tem escopo dinâmico . .bindajusta a thispalavra - chave e isso é próximo, mas tecnicamente não é o mesmo.

Aqui está um exemplo demonstrando as duas abordagens. Você faz isso toda vez que toma uma decisão sobre o escopo de retornos de chamada, para que isso se aplique a promessas, manipuladores de eventos e muito mais.

Lexical

Aqui está o que você pode chamar Lexical Scopingde retorno de chamada em JavaScript:

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

Limite

Outra maneira de escopo é usar Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

Esses métodos são, até onde eu sei, comportamentalmente equivalentes.

SimplGy
fonte
O uso bindnão afeta o escopo.
Ben Aston
12

Escopo léxico: as variáveis ​​declaradas fora de uma função são variáveis ​​globais e são visíveis em todos os lugares em um programa JavaScript. Variáveis ​​declaradas dentro de uma função têm escopo de função e são visíveis apenas para o código que aparece dentro dessa função.

Stan
fonte
12

A IBM define como:

A parte de uma unidade de programa ou segmento na qual uma declaração se aplica. Um identificador declarado em uma rotina é conhecido nessa rotina e em todas as rotinas aninhadas. Se uma rotina aninhada declarar um item com o mesmo nome, o item externo não estará disponível na rotina aninhada.

Exemplo 1:

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

Exemplo 2:

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();
Robert Rocha
fonte
8

O escopo léxico significa que, em um grupo aninhado de funções, as funções internas têm acesso às variáveis ​​e outros recursos do escopo pai . Isso significa que as funções filho estão lexicamente ligadas ao contexto de execução de seus pais. Às vezes, o escopo léxico também é chamado de escopo estático .

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

O que você notará sobre o escopo lexical é que ele funciona adiante, significando que o nome pode ser acessado pelos contextos de execução de seus filhos. Mas não funciona de volta para os pais, o que significa que a variável likesnão pode ser acessada pelos pais.

Isso também nos diz que variáveis ​​com o mesmo nome em diferentes contextos de execução ganham precedência de cima para baixo da pilha de execução. Uma variável, com um nome semelhante a outra variável, na função mais interna (contexto mais alto da pilha de execução) terá maior precedência.

Observe que isso é retirado daqui .

AConsumidor
fonte
8

Em linguagem simples, o escopo lexical é uma variável definida fora do seu escopo ou o escopo superior está automaticamente disponível dentro do seu escopo, o que significa que você não precisa passá-lo para lá.

Exemplo:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// Saída: JavaScript

JKA
fonte
2
A resposta mais curta e a melhor para mim, com um exemplo. Poderia ter sido adicionado que as funções de seta do ES6 'resolvem o problema bind. Com eles, o bindnão é mais necessário. Para obter mais informações sobre essa alteração, verifique stackoverflow.com/a/34361380/11127383
Daniel Danielecki 20/01
4

Falta uma parte importante da conversa em torno do escopo lexical e dinâmico : uma explicação clara do tempo de vida da variável com escopo - ou quando a variável pode ser acessada.

O escopo dinâmico corresponde apenas muito pouco ao escopo "global" da maneira como tradicionalmente pensamos (a razão pela qual eu trago a comparação entre os dois é que ele já foi mencionado - e não gosto particularmente da explicação do artigo vinculado ); provavelmente é melhor não fazermos a comparação entre global e dinâmica - embora supostamente, de acordo com o artigo vinculado, "... [seja] útil como um substituto para variáveis ​​de escopo global".

Então, em inglês simples, qual é a distinção importante entre os dois mecanismos de escopo?

O escopo léxico foi definido muito bem nas respostas acima: variáveis ​​de escopo lexicamente estão disponíveis - ou acessíveis - no nível local da função em que foram definidas.

No entanto - como não é o foco do OP - o escopo dinâmico não recebeu muita atenção e a atenção que recebeu significa que provavelmente precisa de um pouco mais (isso não é uma crítica a outras respostas, mas sim um "oh, essa resposta nos fez desejar que houvesse um pouco mais "). Então, aqui está um pouco mais:

O escopo dinâmico significa que uma variável é acessível ao programa maior durante a vida útil da chamada de função - ou enquanto a função está em execução. Realmente, a Wikipedia realmente faz um bom trabalho com a explicação da diferença entre os dois. Para não ofuscá-lo, eis o texto que descreve o escopo dinâmico:

... [n] escopo dinâmico (ou escopo dinâmico), se o escopo de um nome de variável for uma determinada função, seu escopo será o período de tempo durante o qual a função está executando: enquanto a função está em execução, o nome da variável existe e está vinculado à sua variável, mas após o retorno da função, o nome da variável não existe.

Thomas
fonte
3

O escopo léxico significa que uma função procura variáveis ​​no contexto em que foi definida, e não no escopo imediatamente ao seu redor.

Veja como o escopo lexical funciona no Lisp, se você quiser mais detalhes. A resposta selecionada por Kyle Cronin em variáveis ​​dinâmicas e lexicais no Common Lisp é muito mais clara do que as respostas aqui.

Coincidentemente, eu só aprendi sobre isso em uma classe Lisp, e isso também se aplica ao JavaScript.

Eu executei esse código no console do Chrome.

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

Resultado:

5
10
5
ratiotile
fonte
3

Um escopo lexical em JavaScript significa que uma variável definida fora de uma função pode ser acessada dentro de outra função definida após a declaração da variável. Mas o contrário não é verdadeiro; as variáveis ​​definidas dentro de uma função não estarão acessíveis fora dessa função.

Esse conceito é muito usado em fechamentos em JavaScript.

Digamos que temos o código abaixo.

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

Agora, quando você chama add () -> isso imprimirá 3.

Portanto, a função add () está acessando a variável global xque é definida antes do método function add. Isso é chamado devido ao escopo lexical no JavaScript.

Praveen Kishor
fonte
Considere que o trecho de código era para um idioma com escopo dinâmico. Se a add()função fosse chamada imediatamente após o trecho de código fornecido, ela também imprimiria 3. O escopo lexical não significa simplesmente que uma função pode acessar variáveis ​​globais fora do contexto local. Portanto, o código de exemplo realmente não ajuda a mostrar o significado do escopo lexical. Mostrar o escopo lexical no código realmente precisa de um contra-exemplo ou pelo menos uma explicação de outras possíveis interpretações do código.
C Perkins
2

O escopo lexical refere-se ao léxico dos identificadores (por exemplo, variáveis, funções, etc.) visíveis a partir da posição atual na pilha de execução.

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

fooe barestão sempre dentro do léxico dos identificadores disponíveis porque são globais.

Quando function1é executado, ele tem acesso a um léxico de foo2, bar2, foo, e bar.

Quando function2é executado, ele tem acesso a um léxico de foo3, bar3, foo2, bar2, foo, e bar.

A razão pela qual funções globais e / ou externas não têm acesso a identificadores de funções internas é porque a execução dessa função ainda não ocorreu e, portanto, nenhum de seus identificadores foi alocado para a memória. Além disso, uma vez que o contexto interno é executado, ele é removido da pilha de execução, o que significa que todos os seus identificadores foram coletados como lixo e não estão mais disponíveis.

Finalmente, é por isso que um contexto de execução aninhado SEMPRE pode acessar seu contexto de execução de ancestrais e, portanto, por que ele tem acesso a um léxico maior de identificadores.

Vejo:

Agradecimentos especiais a @ robr3rd pela ajuda na simplificação da definição acima.

Kenneth Stoddard
fonte
1

Aqui está um ângulo diferente sobre essa questão que podemos obter dando um passo atrás e analisando o papel do escopo na estrutura maior de interpretação (executando um programa). Em outras palavras, imagine que você estava construindo um intérprete (ou compilador) para uma linguagem e foi responsável por calcular a saída, dado um programa e alguma entrada para ele.

Interpretação envolve acompanhar três coisas:

  1. Estado - ou seja, variáveis ​​e locais de memória referenciados na pilha e na pilha.

  2. Operações nesse estado - ou seja, todas as linhas de código do seu programa

  3. O ambiente em que uma determinada operação é executada - a saber, a projeção do estado em uma operação.

Um intérprete inicia na primeira linha de código de um programa, calcula seu ambiente, executa a linha nesse ambiente e captura seu efeito no estado do programa. Em seguida, segue o fluxo de controle do programa para executar a próxima linha de código e repete o processo até o término do programa.

A maneira como você calcula o ambiente para qualquer operação é através de um conjunto formal de regras definidas pela linguagem de programação. O termo "ligação" é frequentemente usado para descrever o mapeamento do estado geral do programa para um valor no ambiente. Observe que por "estado geral" não queremos dizer estado global, mas sim a soma total de todas as definições alcançáveis, em qualquer ponto da execução).

Essa é a estrutura na qual o problema de escopo é definido. Agora, para a próxima parte do que são nossas opções.

  • Como implementador do intérprete, você pode simplificar sua tarefa tornando o ambiente o mais próximo possível do estado do programa. Por conseguinte, o ambiente de uma linha de código seria simplesmente definido pelo ambiente da linha de código anterior com os efeitos dessa operação aplicada a ela, independentemente de a linha anterior ser uma atribuição, uma chamada de função, retorno de uma função, ou uma estrutura de controle como um loop while.

Esta é a essência do escopo dinâmico , em que o ambiente em que qualquer código é executado é vinculado ao estado do programa, conforme definido pelo seu contexto de execução.

  • Ou você pode pensar em um programador usando sua linguagem e simplificar sua tarefa de acompanhar os valores que uma variável pode assumir. Existem muitos caminhos e muita complexidade envolvidos no raciocínio sobre o resultado da totalidade da execução passada. O escopo léxico ajuda a fazer isso restringindo o ambiente atual à parte do estado definida no bloco atual, função ou outra unidade de escopo e seu pai (ou seja, o bloco que encerra o relógio atual ou a função que chamou a função atual).

Em outras palavras, com escopo lexical, o ambiente que qualquer código vê é vinculado ao estado associado a um escopo definido explicitamente na linguagem, como um bloco ou uma função.

er0
fonte
0

Pergunta antiga, mas aqui está minha opinião.

O escopo lexical (estático) refere-se ao escopo de uma variável no código-fonte .

Em uma linguagem como JavaScript, onde as funções podem ser passadas, anexadas e reconectadas a objetos diversos, você pode pensar que esse escopo depende de quem está chamando a função no momento, mas não. Alterar o escopo dessa maneira seria um escopo dinâmico, e o JavaScript não faz isso, exceto possivelmente com othis referência objeto.

Para ilustrar o ponto:

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

No exemplo, a variável aé definida globalmente, mas sombreada na doit()função. Esta função retorna outra função que, como você vê, depende doa variável fora de seu próprio escopo.

Se você executar isso, descobrirá que o valor usado é aardvark, não o applequal, embora esteja no escopo dotest() função, não está no escopo lexical da função original. Ou seja, o escopo usado é o escopo que aparece no código-fonte, não o escopo em que a função é realmente usada.

Esse fato pode ter consequências irritantes. Por exemplo, você pode decidir que é mais fácil organizar suas funções separadamente e usá-las quando chegar a hora, como em um manipulador de eventos:

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();
<button id="a">A</button>
<button id="b">B</button>

Este exemplo de código faz um de cada. Você pode ver que, devido ao escopo lexical, o botão Ausa a variável interna, enquanto o botãoB não. Você pode acabar aninhando funções mais do que gostaria.

A propósito, nos dois exemplos, você também observará que as variáveis ​​internas com escopo lexicamente persistem, mesmo que a função da função que contém tenha executado seu curso. Isso é chamado de fechamento e refere-se ao acesso de uma função aninhada a variáveis ​​externas, mesmo que a função externa tenha sido concluída. O JavaScript precisa ser inteligente o suficiente para determinar se essas variáveis ​​não são mais necessárias e, se não, podem ser coletadas pelo lixo.

Manngo
fonte
-1

Normalmente aprendo pelo exemplo, e aqui está uma coisinha:

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();
Karl Morrison
fonte
-1

Este tópico está fortemente relacionado à bindfunção interna e introduzido nas funções de seta do ECMAScript 6 . Foi realmente irritante, porque para cada novo método de "classe" (função realmente) que queríamos usar, precisávamos binddisso para ter acesso ao escopo.

O JavaScript por padrão não definir seu escopo de thisem funções (que não define o contexto em this). Por padrão, você precisa dizer explicitamente qual contexto deseja ter.

As funções de seta obtêm automaticamente o chamado escopo lexical (têm acesso à definição da variável em seu bloco contendo). Ao usar as funções de seta, ele se liga automaticamente thisao local em que a função de seta foi definida em primeiro lugar, e o contexto dessas funções de seta é seu bloco contendo.

Veja como ele funciona na prática nos exemplos mais simples abaixo.

Antes das funções de seta (sem escopo lexical por padrão):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

Com funções de seta (escopo lexical por padrão):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"
Daniel Danielecki
fonte