Solucionado (ver solução)
Solucionado
(ver solução)
17
respostas

Arrow Function setando atributo de classe

Se no function o scope é lexical pq o resultado da function run da undefined em this_a.

show(){
        this._a = 'dasdad'; //dasdad
        let run = () => {
            this._a = 'dasdad';//undefined
        };
    }
17 respostas

Seu código está incompleto. Em que momento você chama run no seu teste? Só vejo a function expression no seu código e não a chamada dela.

O show é de uma classe ou um Object? Poste o código completo.

Desculpe professor, segue um código mais completo como exemplo:

class Pessoa {
    constructor(nome){
        this._nome = nome;
    }
    show(){
        this._nome = 'Maria'; 
        console.log(this._nome);// Maria
        let run = () => {
            this._nome = 'Marcos';
            console.log(this._nome);//undefined
        };
    }
}
let NovaPessoa = new Pessoa('jose');
NovaPessoa.show()

No meu exemplo real, a function run devolve através de uma Promise a string nome. Algo como:

$http.get('url').then(nome => {
    this._nome = nome;
    console.log(this._nome);//undefined
};)

Oi meu aluno! Vamos por partes.

No seu exemplo completo, nenhum erro acontece porque você não chama run. Nele, você guarda uma function expression com arrow function. Mas novamente você não o chamou.

Alterando seu código para chamar run, ele fica assim:

<script>
class Pessoa {
    constructor(nome){
        this._nome = nome;
    }
    show(){
        this._nome = 'Maria'; 
        console.log(this._nome);// Maria
        let run = () => {
            this._nome = 'Marcos';
            console.log(this._nome);/
        };
        run(); // chamei aqui seu código!
    }
}
let NovaPessoa = new Pessoa('jose');
NovaPessoa.show()
</script>

O resultado ocorre como esperado. É impresso Maria e Marcos no console. Você pode testar colocando esse código diretamente dentro de teste.html .

Então, ele demonstra que o escopo da arrow function é léxico.

Contudo, eu preciso do código completo no qual você usa $http do Angular 1. Geralmente, Angular 1 não trabalha com classes e para saber o contexto de this, eu preciso saber de onde $http é chamado.

Fico no aguardo com código completo.

Agora, vamos fazer um revisão de arrow function. Beleza? Ela não possui escopo dinâmico, ela possui um escopo estático e pode ser inferido no local onde ela é declarada. Vejamos seu código:

    show(){


       // QUEM É THIS AQUI, NESSE PONTO? THIS É A INSTÂNCIA DA CLASSE!

        this._nome = 'Maria'; 
        console.log(this._nome);// Maria
        let run = () => {

          // O THIS AQUI CONTINUARÁ SENDO A INSTÂNCIA DA CLASSE, POIS A ARROW FUNCTION NÃO É DINÂMICA, LEVA EM CONSIDERAÇÃO O VALOR DE THIS DEFINIDO ANTERIORMENTE

            this._nome = 'Marcos';
            console.log(this._nome);/
        };
        run(); // chamei aqui seu código!
    }

Então, para que possamos entender o problema do seu código que o levou a desconfiar do this léxico (estático) da arrow function, você precisa compartilhar o código completo, porque nele, não sei qual é o this ao redor da chamada de $http.

Fico no aguardo meu aluno.

Ótimo. Eu já havia cogitado essa possibilidade entretanto desconhecia como efetuar arrow function Immediately invoked.Bastando apenas

 run() // -.-'

Existe a possibilidade de criar arrow function Immediately invoked? Em seguida posto o código do Angular 1. Obrigado pela atenção.

Sim, há. Eu mostro isso no curso avançado, mas você ainda não chegou na parte2 ou parte3.

Exemplo:

(() => {
  // código que você quer executar.
})();

Modificando seu código:

show(){


       // QUEM É THIS AQUI, NESSE PONTO? THIS É A INSTÂNCIA DA CLASSE!

        this._nome = 'Maria'; 
        console.log(this._nome);// Maria
        (() => {

          // O THIS AQUI CONTINUARÁ SENDO A INSTÂNCIA DA CLASSE, POIS A ARROW FUNCTION NÃO É DINÂMICA, LEVA EM CONSIDERAÇÃO O VALOR DE THIS DEFINIDO ANTERIORMENTE

            this._nome = 'Marcos';
            console.log(this._nome);/
        })();
    }

O resultado é o mesmo, tudo continua funcionando como esperado.

Como solicitado, segue meu código real: método ls() de uma class específica:

...
ls(){
       request(`${this._serverAddress}/ls-tree.json`, (error, response, body) => {
            this._shpfile = JSON.parse(body).response.node.map(shp => getJson.shpfile(shp.path));
        })
    }
...

Apesar de no exemplo ter usado a sintaxe do angular 1 como ilustração, utilizo uma biblioteca específica chamada 'request' .

Neste contexto qual seria a melhor abordagem para setar o this._shfile com o resultado da requisição.

Ainda não dá para saber. Talvez você não tenha me entendido. Para saber o valor de this você precisa saber o contexto ao redor. Você esta apenas mostrando para um método ls() que não sei a quem faz parte.

Para eu poder mostrar qual o valor de this, você precisa mostrar o código da classe e como esta associando o método a um controller do Angular. Até porque, já te mostrei que o this é léxico no próprio exemplo que você me passou.

rsrsr, desculpe novamente. A Classe é um pouco extensa. Entretanto segue código resumido como contexto.

var request = require('request');

class Repository  {
    constructor(shpfile = []){
        this._shpfile = shpfile;
    }
    get shpfile (){
        return this._shpfile
    };
    set shpfile (newShpfile){
        this._shpfile = newShpfile
    };

    ls(){
       request(`${this._serverAddress}/ls-tree.json`, (error, response, body) => {
            this._shpfile = JSON.parse(body).response.node.map(shp => getJson.shpfile(shp.path));
        })
    }
}
solução!

Olha, então não é um código angular? É um código que esta sendo rodado no backend em uma API? Esta muito confuso, porque você mencionou Angular, e agora mudou completamente o código.

Parece ser de uma API Node, pois você esta usando require.

Independente do código ser do Angular ou não, há um problema nele que não há relação com arrow function, mas um conceito fundamental de JavaScript.

Seu request executa uma operação assíncrona, você não poderia guardar seu resultado na propriedade da classe, justamente por ele ser assíncrono. Você nunca saberá quando ele será executado e quem acessar a propriedade pode acessá-la como não incializada. (no curso eu guardo em this, porque eu uso no próprio método da classe, não chamo o método da classe de fora).

Talvez seja interessante fazer o curso de JavaScript antes do avançado para ficar ainda melhor sobre esse conceito de cídigo assíncrono.

Para que seu código funcione, você precisa capturar o retorno de request em um callback.

Para ficar mais claro, você pode guardar o resultado sim, mas operá-lo apenas dentro do callback do request.

Outro ponto, você não mostrou o código que tenta acessar a propriedade que é undefined. Isso me faz presumir que você esta instanciando a classe e querendo acessar o valor da propriedade através de outra classe. Isso não vai funcionar como eu disse, porque seu método é assíncrono.

Enfim, a questão aqui não é arrow function ou function, mas como um código assíncrono funciona.

Se você estiver fazendo isso não vai roldar

let  r = new Repository();
r.ls();
console.log(r.shpfile); // undefined

Para que seu código funcione, você precisaria fazer:

let  r = new Repository();
r.ls(shpfile => console.log('faz o que quiser com o resultado');

Como é uma operação assíncrona e você quer usar de fora da classe, precisa passar um callback para que seja possível acessar a resposta.

E seu método ls():

 ls(cb){
       request(`${this._serverAddress}/ls-tree.json`, (error, response, body) => {
            let shpfile = JSON.parse(body).response.node.map(shp => getJson.shpfile(shp.path));
          cb(shpfile);
        })
    }

Uma ultima dúvida, neste exemplo seu:

let  r = new Repository();
r.ls(shpfile => console.log('faz o que quiser com o resultado');

Qual seria a melhor abordagem para com o resultado do callback setar o atributo shpfile na classe existente na variável 'r'.

r.ls(shpfile => {
    r.shpfile = shpfile;
    console.log(r.shpfile)//Objeto retornado de shpfile é empresso.
});
console.log(r.shpfile)//[] vázio.

Não sei se ficou claro mas gostaria de alterar o objeto existente na variável 'r' a partir da execução da requisição async existente no método 'ls()' sem ter que reatribui-lo à uma nova variável.

Comentando seu código:

r.ls(shpfile => {
    r.shpfile = shpfile;
    console.log(r.shpfile)//Objeto retornado de shpfile é impresso.
});
// o código anterior é assíncrono, logo, o código de baixo será executado antes dele terminar, por isso o código é um array vazio.
console.log(r.shpfile)//[] vázio.

Como indiquei antes, se você quiser ter acessado aos dados retornado por ls() que é assíncrono pois usa request, precisará passar um callback como no exemplo que dei.

Operações de I/O são assíncronas e não bloqueantes em JavaScript.