0

I have this function coded:

var Dom = function () {

    this.getX = function (element, value) {
        ... 
    }

    this.checkX = function (label, expectedCount, params) {
        it(label + ': Check for ' + expectedCount, function () {
            for (var i = 0; i < params.length; ++i) {
                this.getX.apply(this, params[i]).click();
            }
        });
    }

It gives me an undefined with getX. How can I make it so the getX will work inside the checkX function?

  • See here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind – elclanrs Jul 13 '14 at 08:31
  • A note: To me it looks like the `it()` of mocha, but the way you use it looks really strange to me. Maybe it is not mocha but if it is you should check if you really use it the right way. – t.niese Jul 13 '14 at 08:47

3 Answers3

1

There are a few ways you can change what this refers to in a function, or otherwise retain access to the outer this. However, we should note that your problem is not with checkX, but with the anonymous function within checkX, so you need to apply one of these techniques to that function.

Storing a reference to this in a variable:

var Dom = function() {
    var self = this;

    this.getX = function(element, value) {
        ...
    }

    this.checkX = function (label, expectedCount, params) {
        it(label + ': Check for ' + expectedCount, function () {
            for (var i = 0; i < params.length; ++i) {
                self.getX.apply(self, params[i]).click();
            }
        });
    }
}

Or using Function.prototype.bind (thanks to elclanrs for mentioning this in the comments):

var Dom = function() {
    this.getX = function(element, value) {
        ...
    };

    this.checkX = function (label, expectedCount, params) {
        it(label + ': Check for ' + expectedCount, (function () {
            for (var i = 0; i < params.length; ++i) {
                this.getX.apply(this, params[i]).click();
            }
        }).bind(this));
    }
}

..Or, by using Function.prototype.call. This technique won't work in your scenario because you don't control when the anonymous function is called, but it's useful to know in general.

var Dom = function() {
    this.getX = function(element, value) {
        ...
    };

    this.checkX = function (label, expectedCount, params) {
        ...
    }

    // when calling checkX later..
    this.checkX.call(this, argument1, argument2, argument3);
}

Many JavaScript libraries contain utilities to easily handle what this refers to, since callback functions are incredibly common in most JS applications. For example, see dojo.hitch or jQuery's $.proxy. You can easily write your own function to do the same:

function WrapCallbackWithContext(context, callback) {
    return function() {
        return callback.apply(context, arguments);
    }
}
Chris Hayes
  • 11,471
  • 4
  • 32
  • 47
  • 1
    OP has the problem because of the inner closure. In your examples, how you wrote it, you don't need it, `this` will refer to the instance inside `this.checkX`. The problem arises when you introduce another scope. – elclanrs Jul 13 '14 at 08:37
  • @elclanrs Quite right - I just submitted an edit for that reason. – Chris Hayes Jul 13 '14 at 08:38
  • 1
    oooooo.... how much I hate `that = this`... I find it causes much unnecessary confusion... Why would you refer to the current "instance" as "that" from within itself? IMO, `self` is the only sane alternative for `this`. – Lix Jul 13 '14 at 08:49
  • 1
    @Lix That's probably a much better choice. I almost never use that idiom myself, preferring to bind `this` in other ways, so I just used the first thing that came to mind. I'll go ahead and change to `self` in case anyone stumbles on this from google though, thanks! – Chris Hayes Jul 13 '14 at 08:53
1

Try preserving the scope in a different variable:

var Dom = function () {
    var self = this;
    this.getX = function ( element, value ) {
        ... 
    }

    this.checkX = function ( label, expectedCount, params ) {
        ...
        self.getX.apply( self, params[ i ] ).click();
        ... 
    }
}

var self = this; preserves the scope of your DOM function inside the self variable. When you get into one of the inner functions, you'll still have access to the self variable and hence still have access to the original scope.

Lix
  • 47,311
  • 12
  • 103
  • 131
-1

It seems that your it function is calling a callback function and inside callback this will not refer to your outer function

var Dom = function () {

    this.getX = function (element, value) {
        ... 
    }
    var _this = this;
    this.checkX = function (label, expectedCount, params) {
        it(label + ': Check for ' + expectedCount, function () {
            for (var i = 0; i < params.length; ++i) {
                _this.getX.apply(this, params[i]).click();
            }
        });
    }
}
Harpreet Singh
  • 2,651
  • 21
  • 31