Jump to content

Closures e funções de ordem superior


pedrotuga
 Share

Recommended Posts

Para quem nunca teve contacto com estes dois conceitos, vou aqui afixar um exemplo simples e explicar estes dois 'truques'.

Em javascript, as funções são 'cidadãos de primeira classe'. Isto na prárica significa que podem ser atribuidas a uma variável. Podem então ser passadas como parâmetros a outras funções ou ser devolvidas por outras funções.

Adicionalmente, as funções correm no ambiente onde foram criadas. Trocado por miudos, retêm o valor das variáveis que estão no mesmo scope onde foram criadas. Isto permite preparar um ambiente atribuindo valores a gosto a quantas variáveis se desejar, e depois criar uma função que usa essas variáveis sem ter que as passar todas como parâmtros.

A esta prática chama-se closure, criar uma função com o seu ambiente pendurado.

Para se criar uma closure, há então que definir uma função num scope sob o qual tenhamos controlo das variáveis metidas ao barulho. O javascript NÃO tem scope de bloco, mas tem scope de função, sendo por isso necessário recorrer a uma função extra para criar um scope. Esta deve embrulhar o nosso ambiente e devolver outra função que o levará consigo.

No exemplo a seguir, demonstro precisamente isso. a função foo recebe um parâmetro e devolve uma função que soma o valor desse parâmetro, ao parâmetro que esta recebe.

Como se pode ver, criei as funções foo2 e foo10 que retêm o valor que a tinha quando foram criadas.

function foo(a){
   var bar = function(b){return a+b;};
   return bar;
}

var foo2 = foo(2);
var foo10 = foo(10);

foo2(1); //devolve 3
foo10(1) //devolve 11

Espero que isto ajude, não usar estas características a linguagem é perder grande parte da sua beleza e utilidade.

Em boa verdade isto não são truques, isto são características fundamentais da linguagem.

Link to comment
Share on other sites

Boas, estou aqui com um problema que se prende percisamente com este assunto, tenho o seguinte código:

function AppsScreen(){
    this.apps=[];
}
AppsScreen.prototype.init=
    function(){
        console.log("initAppsScreen");
        this.loadApps();                //chama o loadApps sem problemas
        $("#apps_screen ul").sortable({
            delay: 500,
            items: 'li',
            update: function(event, ui) {
                this.updateOrderIndexes();
            },
            stop: function(event, ui) {
                this.postUpdateOrder();
            }
        });
        $("#apps_screen ul").disableSelection();
        $("#apps_screen ul img").mousedown(function(event) {
            event.preventDefault();
        });

    }
AppsScreen.prototype.loadApps=
    function(){
        $.ajax({
            type: 'GET',
            url: '/?c=AppsScreen&m=loadApps',
            success: function(data){
                this.apps=data;
                this.drawApps();       //Aqui queixa-se this.drawApps is not a function
            },
            error:function(){
                alert("Error connecting to the server.");
            },
            dataType: 'json'
        });
    }
AppsScreen.prototype.drawApps=
    function(){
        html="";
        $.each(apps,function(app){
            html+="<li class=\"app\" id=\"app_"+this.id+"\" >";
            html+="<img src=\"/assets/images/"+this.icon+"\"/>";
            html+="<div class=\"app_name\">"+this.name+"</div>";
            html+="</li>";
        });
        $("#apps_screen ul").html(html);
    }

pelo que percebi naquela scope o meu this é algo relacionado com o jQuery e nao o objecto da classe AppsScreen. neste caso em que eu tenho vario niveis como é que eu poderia propagar ou referir-me a minha class?

pessoalmente acho js muito versatil bom para pequenos scripts, mas quando tento fazer algo maior torna-se um pouco dificil de estruturar... Muito provavelmente devido á minha falta de experiencia com a linguagem.

Cumprimentos,

KnoKer

Link to comment
Share on other sites

O this é uma referência para o objecto no qual a função é criada. Nesse caso, estás a criar um objecto com as chavetas e estás a definir os atributos: type, url, success, error,datatype.

O jquery nesse caso precisa de receber um objecto com essa estrutura. Antes de chamares o método $.ajax(), cria referências paraas funções ou variáveis que precisares de usar.

Isto deve funcionar:

AppsScreen.prototype.loadApps=
    function(){
        var localDrawApps = this.drawApps;
        var localData;
        $.ajax({
            type: 'GET',
            url: '/?c=AppsScreen&m=loadApps',
            success: function(data){
                localData=data;
                localDrawApps();     
            },
            error:function(){
                alert("Error connecting to the server.");
            },
            dataType: 'json'
        });
     this.data =localData; //não esquecer desta linha
    }
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.