1

I'm defining a Parent object, and I want it to have a child member object that has its own functions and private variables. In order to encapsulate the functions and variables, I'm adding a self-executing anonymous function to the Parent prototype.

Here is code demonstrating the problem:

var Parent = function() {
    this.memberVariable = 'hello world';   
}

Parent.prototype.doSomething = function() {
    return this.childObject.doSomething();
};

Parent.prototype.childObject = function() {
    // instead of being Parent, `this` is the Window object. What is the best way to fix this?
    var that = this;
    
    return {
        doSomething: function() {
            // undefined, but should be 'hello world'
            return that.memberVariable;
        }
    }
}();

var parent = new Parent();
console.log(parent.doSomething());

One workaround I have is passing in the Parent scope to the child functions, but that seems weird, and it seems like there must be a better solution:

var Parent = function() {
    this.memberVariable = 'hello world';   
}

Parent.prototype.doSomething = function() {
    // we pass in `this`
    return this.childObject.doSomething(this);
};

Parent.prototype.childObject = function() {
    return {
        doSomething: function(that) {
            return that.memberVariable;
        }
    }
}();

var parent = new Parent();
console.log(parent.doSomething());

Is there a better way to accomplish this?

brismuth
  • 36,149
  • 3
  • 34
  • 37
  • You should look into the Module/Revealing Module pattern... http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript – An0nC0d3r Nov 02 '15 at 20:37
  • You cannot have an IEFE to create a prototype method and expect to get a dynamic `this` inside there. – Bergi Nov 02 '15 at 20:54
  • Possible duplicate of [Organize prototype javascript while perserving object reference and inheritance](http://stackoverflow.com/q/15884096/1048572) – Bergi Nov 02 '15 at 20:56

2 Answers2

4

Initialize childObject inside the Parent constructor function. Otherwise, all instances of Parent will share the same childObject. That's probably not what you intend.

function Parent() {
  this.childObject = new Child(this); // or something like makeChild(parent), or just an object literal.
}

function Child(parent) {
  this.parent = parent;
}
Trevor Dixon
  • 23,216
  • 12
  • 72
  • 109
  • That hadn't occurred to me because Parent is a singleton, so I wasn't thinking about the scope of the `childObject` definition. This is a much cleaner solution. Thanks! – brismuth Nov 02 '15 at 21:03
0

Use call or apply:

Parent.prototype.doSomething = function() {
    return this.childObject.doSomething.call(this);
};

Or you could use bind:

Parent.prototype.childObject = function() {
    return {
        doSomething: (function() {
            // undefined, but should be 'hello world'
            return this.memberVariable;
        }).bind(this)
    }
}();
Ethan Brown
  • 26,892
  • 4
  • 80
  • 92
  • `.call()` is also one of the things I tried, but I don't like it very much either because it would have to be appended to every single call to `childObject`. Is that the best way to do it? – brismuth Nov 02 '15 at 20:44