0

I have the following structure to my JS:

(function () {
    this.Example = {

        init: function () {

            var self = this;

            var self2 = Example;

            $(document).ready(function () {
                // THIS WORKS
                Example.function1();
                // THIS DOES NOT WORK
                self.function1();
                // THIS DOES NOT WORK EITHER
                self2.function1();
            });

            console.log('init');

        }(),

        function1: function () {
            console.log('function1');
        },

        function2: function () {
            // THIS WORKS
            Example.function1();
            // THIS ALSO WORKS
            this.function1();
            // THIS ALSO WORKS
            var self = this;
            self.function1();
            console.log('function2');
        }
    }
})();

What I'm finding is that when I call a function inside my object literal using this or declaring it on a variable or direct using Example it works fine.

But it in my init() I MUST call it using the literal name and using either this or declaring a variable outside of the document ready still causes errors. Even if declare the variable as var self = Theme it doesn't work and I must call it directly.

Why is this?

Cameron
  • 27,963
  • 100
  • 281
  • 483
  • 4
    It's not clear what works and doesn't work. Please update your question with a clear [mcve] of what doesn't work and a clear [mcve] of what does work, ideally making them **runnable** using Stack Snippets (the `[<>]` toolbar button; [here's how to do one](https://meta.stackoverflow.com/questions/358992/ive-been-told-to-do-a-runnable-example-with-stack-snippets-how-do-i-do-tha)). – T.J. Crowder Nov 20 '17 at 14:35
  • `SyntaxError: missing } after property list` looks like there is a `()` to much at the end of your init declaration. – Roland Starke Nov 20 '17 at 14:35
  • why are you using `$(document).ready(`inside init ? Did you read [Is $(document).ready necessary?](https://stackoverflow.com/questions/4643990/is-document-ready-necessary) – caramba Nov 20 '17 at 14:38
  • @caramba It's just an example (in my real code it is necessary). – Cameron Nov 20 '17 at 14:40
  • @T.J.Crowder Added comments above which calls do and do not work. – Cameron Nov 20 '17 at 14:45
  • Separately: Note that your `init` property will have the value `undefined`, as you immediately call the function and the function doesn't define any particular return value, thus the result of calling it is `undefined`. What is the purpose of the `init` property? – T.J. Crowder Nov 20 '17 at 15:03
  • Regardless of what you put in the `ready` callback, the code presented doesn't run at all. It fails because `Example` is an undeclared identifier you're trying to get the value of in `var self2 = Example;`. – T.J. Crowder Nov 20 '17 at 15:10

2 Answers2

0

You have a few bugs in your code. First off, your this will point to the global window object. In your example, you are actually creating Example as a global variable. See this example:

Note: If you use ES5 Strict Mode, the code below will actually throw an error, as this is not coerced to window in Strict Mode. Instead, you would get undefined as the value of this.

(function() { this.hi = 10; })(); 
console.log(window.hi); // prints 10

Secondly, you should not be setting self to this in your init function because your init is immediately executing in a context that does not have this defined, so this will again point to the window object like in this example:

function Ex() {

    this.Example = {

        // this is coerced to window (in non-Strict Mode)
        init: (function() { console.log(this === window )})()
    }
}

var m = new Ex(); // prints true

Thirdly, you should not be setting self2 equal to Example in your init function, as Example does not yet exist. In the example below, notice that obj is undefined in the console.log statement:

var obj = {

    a : (function() { console.log(obj); })(), // undefined

    b: 7
};

The way I see it, there are several different ways to achieve what you're looking for. The closest solution with similar syntax to what you are currently using would look like so:

Edit: I added examples of how you could use the correct this when registering an event handler in your init, like you are doing in your example with $(document).ready:

function Ex() {

    this.Example = {

        num: 5,

        init: function() {

            // synchronous call
            this.function1();

            // ES6 arrow function to reference "this" 
            setTimeout(() => console.log(this.num), 1000);

            // < ES6 use bind() 
            setTimeout((function() { 

                console.log(this.num); 

            }).bind(this), 2000);
        },

        function1: function() { console.log(this.num); }
    };

    this.Example.init(); // call init() here
}

var m = new Ex(); // initialize your object. 

Further reading:

MDN this - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Christian Santos
  • 5,386
  • 1
  • 18
  • 24
-1

Basically, your scope isn't what you think it is. Your scope changes once the event is called, and it isn't the object anymore.

To be "lazy" and let your thought process work, try using arrow functions. It is much more "forgiving" when it comes to scope.

The following code will print "HI" to the console every time you click the body of the page.

var obj = {
    init: function(){
        var self = this;
        $(document).click(() => this.log("HI"));
    },
    log: function(txt){
        console.log(txt);
    }
}
obj.init();
TheCrzyMan
  • 1,010
  • 1
  • 11
  • 25