1

How do you extend an object prototype with a nested namespace?

http://jsfiddle.net/2t5314nu/2/

I want to be able to call nested methods from Obj.prototype like this.nested.method and be able to access prototype properties and methods from nested as this.prop.

However, when I use jQuery $.extend, the init method from nested overrides the one from Obj.prototype. In fact, Obj.prototype.init is never called.

I want to avoid overriding Obj.prototype.init with nested.init. I would be fine with using something other than $.extend.

function Obj() {
  this.prop = 'val';
  this.init();
}

Obj.prototype = {
  init: function() {
    console.log('object init');
    console.log('prop in object init: ' + this.prop);
    $('#object-init').text('object init');
    this.nested.init();
    this.nested.method();
  }
};

var nested = {
  init: function() {
    console.log('nested init');
    console.log('prop in nested init: ' + this.prop);
    $('#nested-init').text('nested init');
  },
  method: function() {
    console.log('nested method');
    console.log('prop in nested method: ' + this.prop);
    $('#nested-method').text('nested method');
  }
};

$.extend(true, Obj.prototype, nested);

new Obj();
cantera
  • 24,479
  • 25
  • 95
  • 138
  • What behaviour do you expect to see? You've overwritten a function, so the original one is not invoked. – zerkms Nov 10 '14 at 00:27
  • 1
    Instead of `this.nested.init()` try `nested.init.call(this)` – nicosantangelo Nov 10 '14 at 00:32
  • @NicoSantangelo: the prototyped method is not invoked. Not to say that your proposal is just not correct. – zerkms Nov 10 '14 at 00:34
  • @zerkms: My hope is to set the context in `nested` to be `Obj`; that seems to be the main issue I can't figure out: http://jsfiddle.net/2t5314nu/3/ – cantera Nov 10 '14 at 00:55
  • @cantera: the context is resolved in runtime depending how you invoke it. In *your code* you don't invoke it. – zerkms Nov 10 '14 at 00:56
  • @zerkms: Do you mean doing something like `bind(this)` when I call nested methods? Or when I do the `$.extend`? – cantera Nov 10 '14 at 00:59
  • @cantera: No I don't. I mean that in your code you **DO NOT** invoke the prototyped `init` method at all. So it's not obvious what you want to gain with **your** code (not with code someone else provided to you). So what is the "expected" result for your code? `$.extend()` just a dummy "take from here and put there" function, so it's not what causes the problem. – zerkms Nov 10 '14 at 01:01
  • @zerkms: the call to `this.init` in the constructor is intended to call `Obj.prototype.init`. I want to prevent `$.extend` from overriding `Object.prototype.init` with `nested.init`. – cantera Nov 10 '14 at 01:04
  • Well, you've asked it to override it, so it did. What you want instead of overriding? Just remove `init` from `nested` and it will not override it. – zerkms Nov 10 '14 at 01:07
  • Right, and I'm asking how to avoid overriding. I want to be able to call `this.init()` and `this.nested.init()` and have them both work. – cantera Nov 10 '14 at 01:11
  • @cantera: only one function can be available via `this.init`. Ayou could `apply` or `call` then. `this.nested.init.call(this)` – zerkms Nov 10 '14 at 01:19
  • Have you tried passing in "false", instead of "true" in your extend method? When that is the case, I get: object init in your fiddle – james emanon Nov 10 '14 at 01:54

2 Answers2

0

this.nested is undefined in the code you posted. give the nested object a name when you call extend so its added to a particular spot rather than overwriting:

$.extend( true, Obj.prototype, { nested: nested })

Robert Levy
  • 28,747
  • 6
  • 62
  • 94
  • It was not me but it makes sense to put some accompanying text so that it was *helpful* for the OP. And your explanation is actually not consistent "this.nested is undefined in the code you posted" --- is not a problem, since that code is not even running. – zerkms Nov 10 '14 at 00:42
  • +1 for {nested: nested} but unfortunately the Obj.prototype properties are undefined in the nested methods: http://jsfiddle.net/2t5314nu/3/ – cantera Nov 10 '14 at 00:54
-1

You may not know what this in JavaScript is, it's the invoking object so this is the object before the method:

peter.doSomothing();//this in doSomething is peter
peter.nested.doSomething();//this in doSomething is nested
new Person();//when new is used this is the Person instance to be created

You can use .call or .apply when invoking methods of nested to define the invoking object (as already stated in the comments).

function Obj() {
  this.prop = 'val';
  this.init();
}

Obj.prototype = {
  init: function() {
    console.log('in Obj.prototype.init: ' + this.prop);
    nested.init.call(this);
    nested.method.call(this);
  }
};

var nested = {
  init: function() {
    console.log('nested init');
    console.log('prop in nested init: ' + this.prop);
  },
  method: function() {
    console.log('nested method');
    console.log('prop in nested method: ' + this.prop);
  }
};
var o = new Obj();

Or you can have an Obj instance have a Nested instance that has a reference to the Obj:

var Nested = function Nested(objInstance){
  this.objInstance = objInstance;
};
Nested.prototype.init = function init(){
  console.log('init in nested',this.objInstance);
  this.method();
};
Nested.prototype.method = function method(){
  console.log('method in nested',this.objInstance);
};
var Obj = function Obj(){
  this.nested = new Nested(this);
  this.prop='prop of Obj';
};
Obj.prototype.init = function init(){
  console.log('init in Obj',this);
  this.nested = new Nested(this);
};
var objInstance = new Obj();
objInstance.init();
objInstance.nested.init();

More on constructor functions and prototype here: https://stackoverflow.com/a/16063711/1641941

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160