0

I have two different functions who’s values are self-invoking. In each function I have an “init” method. If I use document.ready to fire “init()” inside both functions – they both fire only the last “init”, not their own (so it gets called twice in my example on jsFiddle).

var LightBox = (function(){

    var me = this;
    $(document).ready(function(){ me.init(); });

    me.init = function(){
        console.log('Lightbox Init');
    }
})();

var CustomAnchors = (function(){

    var me = this;
    $(document).ready(function(){ me.init(); });

    me.init = function(){
        console.log('CustomAnchors Init');
    }
})();

This results of this code logs "CustomAnchors Init" twice, but I expect it to log "Lightbox Init" followed by "CustomAnchors Init"

Why is this? And is there a way to avoid this?

  • I think what OP thought they were doing was `LightBox = new function...` That is, using the `new` keyword to instantiate an object. – Jan Sep 13 '15 at 01:20
  • @Jan - I think you're right. That would make sense of the code *and* solve the specific issue they asked about. You should post an answer explaining that in more detail. – nnnnnn Sep 13 '15 at 01:22
  • @nnnnnn I'm afraid at this point it might just confuse OP even more... I'll give it a go, though – Jan Sep 13 '15 at 01:25
  • What is expected result ? – guest271314 Sep 13 '15 at 01:37

3 Answers3

3

You don't really need to do any of that, you should be able to just send in the function directly to document.ready. You don't need to wrap it inside that anonymous function at all:

var LightBox = (function() {
    var init = function(){
        console.log('Lightbox Init');
    }
    $(document).ready(init);
})();

var CustomAnchors = (function(){
    var init = function(){
        console.log('CustomAnchors Init');
    }
    $(document).ready(init);
})();

An explanation of what you were trying to do:
As others have already said, since Lightbox is just a straight up function (even though it's an IIFE), referring to this inside it will just refer to the global object. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

What you're trying to do is refer to this as a custom object, but for that to work you have to instantiate an object. One method to do this is using the new operator, as in new Lightbox() (if Lightbox is a function) or new function() if you want to just create one instance from an anonymous function.

With your specific code it would be

var LightBox = new function() {
    var me = this; // this will now refer to the instantly instantiated LightBox object
    $(document).ready(function(){ me.init(); });

    this.init = function(){ // You could use me.init here but I think it makes for harder-to-understand code
        console.log('Lightbox Init');
    }
};

var CustomAnchors = new function(){
    var me = this; // and same here, for the CustomAnchors object
    $(document).ready(function(){ me.init(); });

    this.init = function(){
        console.log('CustomAnchors Init');
    }
};

But again, you don't really need to wrap it. I'm just explaining here what you were trying to do.

Jan
  • 5,688
  • 3
  • 27
  • 44
  • Your code works in my Firefox 39.0 browser, but I am not sure if this is legal JavaScript. After adding the semicolons in lines 7 and 16 JSHint still complains about "Missing '()' invoking a constructor." and "Weird construction. Is 'new' unnecessary?". I further try to find that kind of construction in David Flanagan's JTDG and only found the `Function` constructor so far which seems to want the body code provided as a string, which is pretty ugly. – mvw Sep 13 '15 at 02:31
  • @mvw it *is* a bit weird, because all it does is basically create an anonymous "class" that will only ever return one single object (unless you hijack the constructor based on the object). The same functionality can be achieved by just creating the object directly, or have an anonymous function return an object. It has the advantage of being able to code as if it is a "class" without having to declare it separately though. I can't find any reference that would claim it was illegal... – Jan Sep 13 '15 at 02:51
  • @mvw - the "Missing ()" warning can be avoided by adding parentheses to the function call in this way: `var LightBox = new function() { } ();` - i.e., after the closing `}`. `new` *is* necessary for this purpose to ensure an object is created. – nnnnnn Sep 14 '15 at 22:27
  • @nnnnnn As far as I can tell this is not a valid JavaScript 1.5 / ECMAScript 3 statement. I am also not able to spot it in the ECMAScript 6 draft, which could be my fault. So I tag it as somewhere between "browser dependent language extension" and "spec unknown to me yet". – mvw Sep 15 '15 at 00:02
  • See http://stackoverflow.com/q/2274695/2579220 ("`new function()` with lower case “f” in JavaScript") as well. – mvw Sep 15 '15 at 00:06
  • @mvw - It's valid. Why wouldn't it be? In that context `function() {}` is a function expression that creates an anonymous function, and `new` calls that anonymous function as a constructor. In my opinion it is neater to include parentheses afterwards as in my previous comment, because it means it's clearer that you're doing it on purpose, but it works without them. The language spec might not include a similar example, but it *does* include function expressions, and `new` is supposed to be followed by a reference to a function, which an anonymous function expression is, so... – nnnnnn Sep 15 '15 at 03:44
2

This seems to work:

var LightBox = (function(){

    $(document).ready(function(){ init(); });

    var init = function(){
        console.log('Lightbox Init');
    };
})();

var CustomAnchors = (function(){

    $(document).ready(function(){ init(); });

    var init = function(){
        console.log('CustomAnchors Init');
    };
})();

The value of this in your example was not the function object you expected.

mvw
  • 5,075
  • 1
  • 28
  • 34
  • 1
    Correct answer. Moreover, to understand what happened in former code, we should try to analyse it. The problem was, that `me` was assigned to `this` and because of a nature `this` is equal there to `window`, so author was overwriting the init() method in CustomAnchors. It's easy to understand here https://jsfiddle.net/d22yzz1p/7/ – Kamil Szymański Sep 13 '15 at 01:06
  • 1
    If you're going to make `init` a local variable, you might as well just remove the variable entirely and pass the anonymous function directly to `.ready()`. – nnnnnn Sep 13 '15 at 01:17
  • Yes, the variable `init` is unnecessary in this example. – mvw Sep 13 '15 at 01:19
  • `this` is the global object, so both functions are assigning to the same init property – Ruan Mendes Sep 13 '15 at 01:41
1

Try returning functions from both LightBox , CustomAnchors ; utilizing .ready() outside of IIFE with variables LightBox , CustomAnchors as functions within array to be called by .ready()

var LightBox = (function(){
        
    return function(){
        console.log('Lightbox Init');
    }

})();

var CustomAnchors = (function(){
    
    return function(){
        console.log('CustomAnchors Init');
    }
    
})();

$(document).ready([LightBox, CustomAnchors])
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
guest271314
  • 1
  • 15
  • 104
  • 177