How to call 'this' outside the scope of my objects?

I developed some Jcrop initialization for the website, I managed to create my own namespace. Question: I am talking about a keyword . Every time I had to access the base object "aps" in any callback function, I have to move this to a variable (I selected the word that ). Is there a better way to do this? For example, is it possible to use calling or applying methods? This is just a namespace, so I could use simple aps. method name, but for this example, please do not mind. Here is my source code:

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=cx; that.form.x2.value=c.x2; that.form.y1.value=cy; that.form.y2.value=c.y2; that.form.h.value=ch; that.form.w.value=cw; } 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; } }); }); 
+6
source share
2 answers

Anytime a function is called using a function call * , this set to a global variable (or undefined in strict mode) - even if you call the function from a method, Douglas Crockford actually described it as a flaw in this language.

Storing the this value in a variable that the function will have access to is the standard way to deal with this.

If you really want to control what this in your callback, you can use apply or call . Both take as the first argument that you want to set this . The difference is that apply expects all function arguments to be passed as an array, and call expects you to list them separately.

So, if you wanted to call manageIframeResponse in your ajax manageIframeResponse , give it an answer to the ajax call (I know your example did not pass the answer, I just illustrate how you will do it) and the value of this will be the same as the current object , You can do:

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

Or, since your parameters are not yet in array form, you can simply use call

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

* There are various ways to call a function.

A function call means that you simply call a function that is in your current scope:

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

A method call means that you are calling a function attached to an object

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

Here's an example of where it might touch you if you're not careful.

 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 no someField return { x: "Hi", someField: "blah", foo: function () { alert(this.x); privateFunc(); } }; } 
+7
source

Consider this:

 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; })(); 
+2
source

Source: https://habr.com/ru/post/903208/


All Articles