2011-12-06 7 views
6

He desarrollado algún tipo de inicialización de Jcrop para un sitio web, logré hacer mi propio espacio de nombre. La pregunta que tengo es con respecto a esta palabra clave. Cada vez que tuve que acceder a mi objeto base "aps" en cualquier función de devolución de llamada, debo envolver este en una variable (he elegido la palabra que). ¿Hay alguna forma mejor de hacerlo? Por ejemplo, ¿puedo usar llamada o aplicar los métodos? Esto es solo un espacio de nombres, así que podría usar simples aps.methodName pero por el bien de este ejemplo, no te moleste. Aquí está mi código fuente:cómo llamar 'esto' fuera del alcance de mis objetos?

var aps; 

$(function(){ 
    aps = function(){ 

     // private 
     // variables 

     var bgColor = '#f5f5f5'; 
     var threshold = 370; 
     var threshold_width = 800; 

     return { 
      tmpl    :  $('#jcrop-template').html(), 
      upl_cont   :  {}, 
      form    :  {}, 
      logo_img   :  new Image(), 
      jcrop_api   :  null, 
      scaled_logo_url   :  '', 
      image_filename   :  '', 
      original_image_filename  :  '', 
      mime    :  '', 
      trueSize   :  '', 

      jcrop_init   :  function (oiFrameRes){ 
       $('#logo_upload_form').find('img').hide(); 
       this.scaled_logo_url = oiFrameRes.image_url; 
       this.logo_url = oiFrameRes.original_image_url; 
       this.original_image_filename = oiFrameRes.original_image_filename; 
       this.image_filename = oiFrameRes.image_filename; 
       this.mime = oiFrameRes.mime; 
       this.upl_cont = $('#facebox div#upload-container-d'); 
       this.logo_img = new Image(); 
       this.logo_img.that  = this; 
       this.logo_img.name  = 'logo'; 
       this.logo_img.onload = function(){ 
        this.true_width=this.width; 
        this.true_height=this.height; 
        this.that.resize_image(); 
        this.that.resize_facebox(); 
        this.that.display_image(); 
       } 
       this.logo_img.src = this.logo_url; 
      }, 

      resize_image   :  function(){ 
       this.trueSize = ''; 
       if(typeof (this.oSettings.trueSize)!=='undefined') delete(this.oSettings.trueSize); 
       if (this.logo_img.width > threshold){ 
        if (this.logo_img.width > threshold_width){ 
         this.trueSize = [ this.logo_img.width, this.logo_img.height ]; 
         this.logo_img.height = this.logo_img.height/(this.logo_img.width/threshold_width); 
         this.logo_img.width = threshold_width; 
        } 
       } 
      }, 

      resize_facebox   :  function(){ 
        var width = (this.logo_img.width > threshold) ? this.logo_img.width : threshold ; 
        $('#facebox').css({ 
         left : $(window).width()/2 - width/2 
        }). 
        find('div.change-size').css({'width': width+30}); 
      }, 

      display_image : function(){ 
       if (this.jcrop_api === null) { 
        $logo_img = $(this.logo_img).css({'display':'block','margin-left':'auto','margin-right':'auto'}) 
        if (this.upl_cont.find('#logo-container-d>img').length > 0){ 
         if (this.upl_cont.find('#logo-container-d>img').attr('src').length > 0){ 
          this.upl_cont.find('#logo-container-d').empty().append($logo_img); 
         } 
        } 
        else { 
         this.upl_cont.append(this.tmpl).find('#logo-container-d').append($logo_img); 
        } 

        var that = this; 
        if (typeof (this.upl_cont.find('#jcrop-menu1 a').data('events')) === 'undefined'){ 
         this.upl_cont.find('#jcrop-menu1 a').click(function(){ 
          if (this.href.indexOf('#crop')>-1){ 
           $(this).closest('div').hide(); 
           that.upl_cont.find('#jcrop-menu2').show(); 
           that.setup_crop(); 
          } 
          if (this.href.indexOf('#close')>-1){ 
           manageIframeResponse(); 
          } 
          location.hash = ''; 
          return false; 
         }); 
        } 
       } 
       else { 
        this.reset(); 
       } 
      }, 

      reset : function(){ 
       $('#jcrop-menu2',this.upl_cont).find('a').unbind('click').end().hide(); 
       $('#jcrop-coords-f',this.upl_cont).find('input[type="text"]').each(function(){this.value="";}).end().hide(); 
       $('#jcrop-menu1',this.upl_cont).find('a').unbind('click').end().show(); 
       this.jcrop_api.destroy(); 
       this.jcrop_api=null; 
       this.display_image(); 
      }, 

      send_form : function(){ 
       var sPost = $(this.form).find('input[name="image_filename"]').val(this.image_filename).end() 
         .find('input[name="original_image_filename"]').val(this.original_image_filename).end() 
         .find('input[name="mime"]').val(this.mime).end() 
         .find('input[name="user_url"]').val($('#logo_upload_base_url').val()).end() 
         .find('input[name="user_key"]').val($('#logo_upload_user_key').val()).end() 
         .serialize(); 

       $.ajax({ 
        url:'iframe_upload.php', 
        type:'POST', 
        data: sPost, 
        success : function(response){ 
         manageIframeResponse(); 
        }, 
        dataType : 'json' 
       }); 
      }, 

      setup_crop : function(){ 

       var that = this; 
       if (this.jcrop_api === null) { 
        this.form = this.upl_cont.find('form#jcrop-coords-f').get(0); 
        this.upl_cont.find('#jcrop-menu2>a').click(function(){ that.send_form();return false; }); 
        this.updateForm = function(){ 
         var c = arguments[0]; 
         that.form.x1.value=c.x; 
         that.form.x2.value=c.x2; 
         that.form.y1.value=c.y; 
         that.form.y2.value=c.y2; 
         that.form.h.value=c.h; 
         that.form.w.value=c.w; 
        } 

        this.oSettings.onSelect = this.updateForm; 
        if (typeof (this.trueSize) !== 'string' && $.isArray(this.trueSize)){ 
         $.extend(this.oSettings,{'trueSize':this.trueSize}); 
        } 
        $('#facebox #logo-container-d>img').Jcrop(this.oSettings, function(){ 

         that.jcrop_api = this; 
         var _x1 = (that.logo_img.true_width*0.1).toFixed(); 
         var _y1 = (that.logo_img.true_height*0.1).toFixed(); 
         var _x2 = (that.logo_img.true_width*0.9).toFixed(); 
         var _y2 = (that.logo_img.true_height*0.9).toFixed(); 
         that.jcrop_api.setSelect([0,0,that.logo_img.true_width,that.logo_img.true_height]); 
         that.jcrop_api.animateTo([_x1,_y1,_x2,_y2]); 
        }); 
       } 
      }, 

      updateForm : function(){}, 

      oSettings : { 
       onSelect:'', 
       onChange:'', 
       keySupport: false, 
       bgColor:bgColor, 
       aspectRatio:1, 
       minSize:[0,0] 
      } 
     } 
    }(); 

    $(document).bind('afterClose.facebox', function() { 
     if (aps.jcrop_api !=null) { 
      aps.jcrop_api.destroy(); 
      aps.jcrop_api=null; 
     } 
    }); 
}); 
+0

no veo un punto en la asignación de la variable de aps' '* * dentro de un manejador de listas ... Está a asignar una función a la misma, no necesito el controlador listo aquí ... –

+0

Creo que lo estás haciendo mal. Desea invocar esa función de inmediato, para que el objeto de retorno se asigne a 'aps' ... –

+0

Hola, no entiendo lo que implica. ¿Qué es un manejador listo y por qué lo estoy haciendo mal? Cuando comencé a escribirlo, sabía que quería encapsularlo, para que nada pudiera acceder a mis funciones sin un espacio de nombres. – Marecky

Respuesta

7

Cada vez que se invoca una función usando la función de invocación *, el valor this se establece en la variable global (o undefined en modo estricto) -incluso si se llama a la función de una método. Douglas Crockford ha descrito esto como un defecto en el lenguaje.

Guardar el valor this en una variable a la que la función tendrá acceso es la manera estándar de tratar con esto.

Si realmente quiere controlar lo que es this en su devolución de llamada, se puede usar apply o call. Ambos toman como primer argumento lo que quiere this para configurar. La diferencia es que apply espera que todos los argumentos de la función se pasen como una matriz, mientras que call espera que los liste en forma individual.

Entonces, si en su devolución de llamada ajax, quería llamar al manageIframeResponse, páselo por la respuesta de la llamada ajax (sé que su ejemplo no pasó la respuesta, solo estoy ilustrando cómo lo haría), y su valor this sea el mismo que el objeto actual, se podría hacer:

var self = this; 
$.ajax({ 
    success : function(response){ 
     manageIframeResponse.apply(self, [response]); //<--- apply wants your arguments in array form 
    } 
}); 

O, ya que sus parámetros no están ya en forma de matriz, podría simplemente utilizar más call

var self = this; 
$.ajax({ 
    success : function(response){ 
     manageIframeResponse.call(self, response); //<---call takes the arguments listed out one at a time 
    } 
}); 

* Existen diferentes formas de invocar una función.

Función invocación significa que sólo está llamando a una función que pasa a ser en el ámbito actual:

foo() //inside foo, this will be the global object (or undefined in strict mode) 

Método de invocación significa que usted está llamando a una función que es asociado a un objeto

myObj.foo() //inside foo, this will be myObj 

Aquí es un ejemplo de que esto puede tropezar si estás ni cuidado.

function objCreator() { 
    var y = "There"; 

    function privateFunc() { 
     alert(y); //alerts There as expected 
     alert(this.someField); //undefined: whoops - this is the global object, 
    }       //so there's no someField 

    return { 
     x: "Hi", 
     someField: "blah", 
     foo: function() { 
      alert(this.x); 
      privateFunc(); 
     } 
    }; 
} 
+0

Si invoca la función como un método, el valor 'this' se refiere al objeto que posee ese método, no al objeto global. –

+0

@ ŠimeVidas - Lo sé. Voy a editar para ser más claro. –

+0

La terminología ("invocación de función") es engañosa o al menos confusa para las personas que no han leído profundamente Crockford y/o la especificación. Que es la mayoría de las personas :-) En lugar de eso, simplemente elija un lenguaje más simple: "En JavaScript, a diferencia de otros idiomas,' this' está configurado completamente por * cómo * se llama una función, no donde se define. " y luego puedes dar ejemplos de los tres tipos de invocación relevantes (no entraría en funciones de constructor a menos que la pregunta usara uno). Mi $ 0.02. :-) –

2

Considere esto:

var aps = (function() { 

    // private variables 
    var private1; 
    var private2; 
    var private3; 

    var aps = {}; // the core object 

    aps.setup_crop = function() { 
     // use "aps" to access the core object 
     if (!aps.jcrop_api) { // etc. 
    }; 

    // define other methods analogously 

    return aps; 
})(); 
Cuestiones relacionadas