Search code examples
javascriptclassjoomlamootools

"this" in .each function not pointing to .each's caller


In jQuery,

$('.myClass').each(function(){return this;})

will retrun every elements with class .myClass. I suppose this is also the case for mootools's .each function. However, when I try to read the following codes, I got confused(the 'attach' function is the method in question, so you can skip other codes):

var Mosaic = new Class({

        Implements: //some codes,

        options: //some codes

        initialize: function(options){
            this.setOptions(options);

            this.mosaics = document.getElements('[data-mosaic]');
            this.mosaic = {};
            this.settings = {};
            try {
                RokMediaQueries.on('every', this.mediaQuery.bind(this));
            }
            catch(error) { if (typeof console != 'undefined') console.error('Error while trying to add a RokMediaQuery "match" event', error); }
        },

        attach: function(mosaic, settings){
            mosaic = typeOf(mosaic) == 'number' ?
                    document.getElements('[data-mosaic=' + this.getID(mosaic) + ']')
                    :
                    mosaic;
            settings = typeOf(settings) == 'string' ? JSON.decode(settings) : settings;

            var containers = (mosaic ? new Elements([mosaic]).flatten() : this.mosaics);

            containers.each(function(container){
                container.store('roksprocket:mosaic:attached', true);
                this.setSettings(container, settings, 'restore');
                // ..... 

        setSettings: //some functions
        // .....
    });

In the 'attach' method, there is a call of containers.each, wherein 'this' is not pointing to the current element of 'containers', insteadly, it is pointing to the instances created through Mosaic CLass. Somewhere in the codes, there is something like:

myDemonstrate = new Mosaic();
myDemonstrate.attach(somekey, someJson);

And I set a breakpoint on the line

this.setSettings(container, settings, 'restore');

and at this point, "this" is actually the object myDemonstrate.

So, why is the "this" here not the .each functions's caller? Does it have to do with the fact that it is inside the Mosaic() function?

(RokSprocketMosaic is a joomla extension developed by RocketTheme, if needed, you can find Mosaic.js file here: http://fbnychoir.org/components/com_roksprocket/layouts/mosaic/themes/default/mosaic.js)


Solution

  • The MooTools .each() iterator behaves like ES5's .forEach() i.e. it will pass the array element and resp index to the function. And the this corresponds to the execution context, or can be set by passing the bind argument to the method.

    As @DimitarChristoff refered in the comments, if the bindargument is not supplied, the this will depend on your document standards mode - either global object or undefined in strict mode. under.

    Excert from the docs at mootools.net:

    Array method: each()

    Calls a function for each element in the array.

    Syntax:

    myArray.each(fn[, bind]);
    

    Arguments:

    1. fn - (function) The function which should be executed on each item in the array. This function is passed the item and its index in the array.
    2. bind - (object, optional) The object to be used as 'this' in the function. For more information see [Function:bind][].

    Argument: fn

    Syntax: fn(item, index, array)

    Arguments:
    1. item - (mixed) The current item in the array.
    2. index - (number) The current item's index in the array.
    3. array - (array) The actual array.

    Examples:

    //Alerts "0 = apple", "1 = banana", and so on:
    
    ['apple', 'banana', 'lemon'].each(function(item, index){
        alert(index + " = " + item);
    }); 
    
    //The optional second argument for binding isn't used here.
    

    So the this, in your code, corresponds to the MooTools Class, so calling this.setSettings() will call the Class's method setSettings which is the last line of the code you posted.