3

Alright I have a question and I don't know the answer. I am creating an object and the properties of the object are constructor functions. Now within these constructor functions I am referencing this. Would the variable this be referring to the parent object, so if I am creating this.submit in each of the constructors would it be overwriting the previous definition?

The reason I am doing this is because I am looping through each property in my object and if it is a function then I am extending its prototype with Node's Event Emitter so I can dispatch events after successful ajax calls.

Here's an example:

var AccountMethods = function(apiVersion){

    return {
        /** Used to login users
         *
         * @param username - {string} Username
         * @param password - {string} Password
         * @function
         *
         * @example
         * var Login = new Easy.Login('fakeusername', 'fakepassword')
         * Login
         *     .on('done', function(data){
         *         if(data.success){
         *              // user is logged in
         *         } else{
         *             throw new Error(data.error);
         *         }
         *     })
         *     .on('error', function(err){
         *         // do something with err
         *     });
         */
        Login: function (username, password) {
            this.submit = function () {
                $.post(apiVersion + 'account/login', {
                    username: username,
                    password: password
                })
                    .done(function (data) {
                        if(data.success){
                            this.emit('done', data);
                        } else{
                            this.emit('error', data)
                        }
                    }.bind(this))
                    .fail(function (err) {
                        this.emit('error', {
                            error: err.status + ' ' + err.statusText + ' : ' + err.responseText
                        });
                    }.bind(this));
            }
        },
        /** Used to logout users
         *
         * @function
         *
         * @example
         * var Logout = new Easy.Logout();
         *
         * Logout.on('done', function(){
         *     // user is logged out
         * });
         *
         * Logout.submit();
         */
        Logout: function () {
            this.submit = function () {
                $.post(apiVersion + 'account/logout')
                    .done(function (data) {
                        this.emit('done');
                    }.bind(this))
                    .fail(function (err) {
                        this.emit('error', err);
                    }.bind(this));
            }
        },
    }
}

You can see within the comments example usage. This definitely works the way I want it to, however is it right?

I can do this and it works as expected:

var Login = new Easy.Login('fakeusername', 'fakepassword');
Login.submit();

var Logout = new Easy.Logout();
Logout.submit();

Both submit functions are set within the same parent object using this.submit = ... but it works as expected. Can someone explain this to me?

pizzarob
  • 11,711
  • 6
  • 48
  • 69
  • 1
    If you are calling the `Login` or `Logout` from the parent Object, then `this` would refer to the Parent Object. But you are creating `Login` and `Logout` objects, so this is expected – kiran Aug 09 '15 at 19:35
  • For a full description of how `this` works, see this answer: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628?s=1|3.8039#13441628. Basically, unless you show us how the functions are called we can't tell you what the value of `this` is. – slebetman Aug 09 '15 at 20:35
  • @slebetman I show a usage example – pizzarob Aug 10 '15 at 06:22
  • @realseanp: See the answer I linked above. – slebetman Aug 11 '15 at 01:15

1 Answers1

2

When you're calling a constructor function with new, a new, empty object is bound to it as this, so inside the function this will refer to the new object that is being created (ie. what will be returned from the new Link() call.) That means in your example the variables Login and Logout are different objects, with different submit methods.

If somebody tried calling Login without new, then the value of this would depend on the calling context: if called as Easy.Login, then this would refer to Easy, but if called as a function reference directly, then the value of this will depend on whether you have strict mode enabled or not. (See Matt Browne's comment below)

All in all: as long as you're using them only as constructor functions, this approach is correct. But as you see, not calling constructor functions as they were designed to be called can be problematic, hence the convention that constructor functions' names start with capital letters (which you are following correctly), so people don't make the mistake of calling them without new (most static code analyzers will warn you by default for not following this convention).

doldt
  • 4,466
  • 3
  • 21
  • 36
  • 1
    Nice answer. Note that you can also add `"use strict";` to the top of each constructor function to make it run in strict mode to prevent incorrect usage...it will ensure that if someone tries to call one of the constructors without `new`, it won't work (since `this` will be undefined). – Matt Browne Aug 09 '15 at 19:54
  • 1
    Actually, I thought it would help more than it does in this case...I just tested it and `this` would only be undefined if you assigned the constructor to a variable first, e.g. `var Login = Easy.Login; Login(username, password)`. As stated by @doldt, "if called as Easy.Login, then this would refer to Easy". So I guess if you're really concerned about incorrect usage by other programmers forgetting to use `new`, you'd have to use a different approach, e.g. you could add this to the top of `Login`: `if (!(this instanceof Login)) return new Login(username, password)` – Matt Browne Aug 09 '15 at 20:05