admin管理员组

文章数量:1420112

I have developed some sort of Jcrop initialization for a website, I managed to make my own namespace. Question I have is regarding this keyword. Every time I had to access my base object "aps" in any callback function I must wrap this in a variable (I have chosen word that). Is there any better way to do it? For example can I use call or apply methods? This is just a namespace so I could use simple aps.methodName but for sake of this example, please don't mind it. 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=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;
        }
    });
});

I have developed some sort of Jcrop initialization for a website, I managed to make my own namespace. Question I have is regarding this keyword. Every time I had to access my base object "aps" in any callback function I must wrap this in a variable (I have chosen word that). Is there any better way to do it? For example can I use call or apply methods? This is just a namespace so I could use simple aps.methodName but for sake of this example, please don't mind it. 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=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;
        }
    });
});
Share Improve this question asked Dec 6, 2011 at 16:26 MareckyMarecky 2,1162 gold badges27 silver badges41 bronze badges 5
  • I don't see a point in assigning the aps variable inside a ready handler... You're just assigning a function to it, you don't need the ready handler here... – Šime Vidas Commented Dec 6, 2011 at 16:29
  • I think you're doing it wrong. You want to invoke that function immediately, so that the return-object is assigned to aps... – Šime Vidas Commented Dec 6, 2011 at 16:31
  • Hi, I don't understand what You imply. What is a ready handler and why am I doing it wrong? When I began writing it I just knew that I wanted to encapsulate it, so nothing could access my functions without a namespace. – Marecky Commented Dec 7, 2011 at 16:28
  • A ready handler is a function that is passed in into the $() function, like so: $(function () { ... });. We use ready handlers to ensure that the web-page (the DOM) is ready, so that our code can operate upon it. In your case, you're just assigning a collection of functions to the aps variable - this is independent of the DOM, and can therefore be done immediately; you don't have to place it into the ready handler. Ignore my second ment - I hadn't noticed that you invoked that function via (). Usually, when invoking function expressions immediately... – Šime Vidas Commented Dec 7, 2011 at 19:16
  • ... you want to put the function expression in parens, like so (function () { ... })() so that it's clear that it's an immediately invoked function expression, and not a regular function. – Šime Vidas Commented Dec 7, 2011 at 19:16
Add a ment  | 

2 Answers 2

Reset to default 8

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

Saving the this value into a variable that the function will have access to is the standard way of dealing with this.

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

So if, in your ajax callback, you wanted to call manageIframeResponse, pass it the ajax call's response (I know your example didn't pass the response, I'm just illustrating how you would do it), and have its this value be the same as the current object, you could do:

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

Or, since your parameters aren't already in array form, you could more 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 different ways to invoke a function.

Function invocation means you're just calling a function that happens to be in your current scope:

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

Method invocation means that you're calling a function that's attached to an object

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

Here's an example of where this can trip you up if you're nor 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's no someField 

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

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

本文标签: javascripthow to call 39this39 outside my objects scopeStack Overflow