2011-12-06 29 views
6

Tôi đã phát triển một số loại khởi tạo Jcrop cho một trang web, tôi đã quản lý để tạo không gian tên của riêng mình. Câu hỏi tôi có liên quan đến từ khóa này. Mỗi lần tôi phải truy cập đối tượng cơ sở "aps" trong bất kỳ chức năng gọi lại nào, tôi phải quấn số này vào một biến (Tôi đã chọn từ ). Có cách nào tốt hơn để làm điều đó không? Ví dụ: tôi có thể sử dụng gọi hoặc áp dụng các phương thức? Đây chỉ là một không gian tên vì vậy tôi có thể sử dụng đơn giản aps.methodName nhưng vì mục đích của ví dụ này, xin đừng bận tâm. Đây là mã nguồn của tôi:cách gọi 'this' bên ngoài phạm vi đối tượng của tôi?

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

Tôi không thấy một điểm trong giao 'aps' biến * bên * một handler sẵn sàng ... Bạn chỉ cần gán một hàm với nó, bạn không cần trình xử lý sẵn sàng ở đây ... –

+0

Tôi nghĩ bạn đang làm sai. Bạn muốn gọi hàm đó ngay lập tức, để đối tượng trả về được gán cho 'aps' ... –

+0

Xin chào, tôi không hiểu bạn ngụ ý gì. _A handler_ sẵn sàng là gì và tại sao tôi làm sai? Khi tôi bắt đầu viết nó tôi chỉ biết rằng tôi muốn đóng gói nó, vì vậy không có gì có thể truy cập các chức năng của tôi mà không có một không gian tên. – Marecky

Trả lời

7

Bất cứ lúc nào một hàm được gọi bằng chức năng gọi *, giá trị this được thiết lập để biến toàn cầu (hoặc undefined trong chế độ nghiêm ngặt) -even nếu bạn gọi hàm từ phương pháp. Douglas Crockford đã thực sự mô tả đây là một lỗ hổng trong ngôn ngữ.

Lưu giá trị this thành biến mà hàm sẽ có quyền truy cập là cách tiêu chuẩn để xử lý vấn đề này.

Nếu bạn thực sự muốn kiểm soát this là những gì trong callback của bạn, bạn có thể sử dụng apply hoặc call. Cả hai đều là đối số đầu tiên bạn muốn đặt this. Sự khác biệt là apply hy vọng tất cả các đối số của hàm sẽ được truyền dưới dạng mảng, trong khi call hy vọng bạn sẽ liệt kê riêng từng đối số. Vì vậy, nếu, trong callback ajax của bạn, bạn muốn gọi manageIframeResponse, vượt qua nó phản ứng của cuộc gọi ajax (tôi biết ví dụ của bạn đã không vượt qua phản ứng, tôi chỉ minh họa cách bạn sẽ làm điều đó), và có giá trị của nó this được giống như các đối tượng hiện tại, bạn có thể làm:

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

Hoặc, vì thông số của bạn là chưa ở dạng mảng, bạn đơn giản hơn có thể sử dụng call

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

* Có nhiều cách khác nhau để gọi hàm.

Chức năng gọi có nghĩa bạn chỉ cần gọi một hàm mà sẽ xảy ra là trong phạm vi hiện tại của bạn:

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

Phương pháp gọi có nghĩa là bạn đang gọi điện thoại một chức năng đó là gắn liền với một đối tượng

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

Đây là ví dụ về nơi bạn có thể đi du lịch nếu bạn cũng không cẩn thận.

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

Nếu bạn gọi hàm là phương thức, giá trị 'this' này đề cập đến đối tượng sở hữu phương thức đó, không phải đối tượng chung. –

+0

@ ŠimeVidas - Tôi biết. Tôi sẽ chỉnh sửa để rõ ràng hơn. –

+0

Thuật ngữ ("gọi hàm") gây hiểu lầm hoặc ít gây nhầm lẫn cho những người chưa đọc Crockford và/hoặc thông số kỹ thuật sâu sắc. Đó là hầu hết mọi người. :-) Thay vào đó, chỉ cần chọn ngôn ngữ đơn giản hơn: "Trong JavaScript, không giống như một số ngôn ngữ khác,' this' được đặt hoàn toàn bằng cách * cách * một hàm được gọi, không phải vị trí được xác định. " và sau đó bạn có thể đưa ra các ví dụ về ba loại yêu cầu có liên quan (tôi sẽ không đi vào các hàm xây dựng trừ khi câu hỏi được sử dụng một). $ 0,02 của tôi. :-) –

2

Hãy xem xét điều này:

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; 
})(); 
Các vấn đề liên quan