2

First of all, I'm attempting to use faux namespaces in my JavaScript program like so:

// Ish.Com namespace declaration
var Ish = Ish || {};
Ish.Com = Ish.Com || {};

// begin Ish.Com.View namespace
Ish.Com.View = new function() {
  var privateVariable;

  this.publicFunction = function() {
    this.publicFunction2()
  };

  this.publicFunction2 = function() { ... };
};

I'm not crazy about using this to call other functions, but up to recently, it has worked. However, I've added event listeners to some elements, and they interpret this to be the target object.

I know I can use the full namespace instead of this to call functions inside of my listeners (Ish.Com.View.publicFunction2()), but the listeners often call one function, which calls another, and another. I'd need to use the entire namespace in nearly every function call.

How can I get namespaces to work nicely with Event Listeners? I'd also be interested in a better way of implementing namespaces, since using this.publicFunction2() is clunky.

I'm very interested in best-practices, and learning how to write a well architected application in JavaScript. However, frameworks are out of the question until I gain a more thorough understanding of JavaScript.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Ishmael Smyrnow
  • 942
  • 1
  • 9
  • 27
  • Could you provide an example of how you bind the event listeners? – Felix Kling May 31 '11 at 14:37
  • `var clickListener = function(e) { ... };` `canvas.addEventListener("click", clickListener, false);` – Ishmael Smyrnow May 31 '11 at 15:10
  • 1
    Mozilla has a good explanation of this problem and solution [here](https://developer.mozilla.org/en/DOM/element.addEventListener#section_8) – Ishmael Smyrnow May 31 '11 at 15:34
  • 1
    *the listeners often call one function, which calls another, and another*... you only have to call the first function the right way. E.g. `clickListener = function(){Ish.Go.View.publicFunction2()}`. There is not so much difference to use `Ish.Go.View.publicFunction2.bind(Ish.Go.View)` or `function() { var view = Ish.Go.View; view.publicFunction2(); }`. – Felix Kling May 31 '11 at 15:41
  • @Felix I actually took this method, and limited my calls inside the listeners. I worry that using bind() would confuse someone who is accustomed to `this` referring to the target object inside of an event listener. – Ishmael Smyrnow May 31 '11 at 16:57

3 Answers3

4

Seems like I've been answering every question this morning the same way :-)

You can use ".bind()":

   var eventHandler = yourObject.someFunction.bind(yourObject);

That'll guarantee that this will refer to "yourObject" whenever the "eventHandler" is called by anything.

The "bind()" function is there on the Function.prototype object in newer browsers. The Mozilla docs include a solid implementation of "bind()" you can use to patch older browsers.

What "bind()" does is return you a new function that explicitly arranges for this to be bound as you stipulate. You can also pass arguments to be passed in, if you like. An alternative to using "bind()" is to wrap the function call in your own anonymous function:

  var eventHandler = function() { yourObject.someFunction(); };
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 1
    All the popular Javascript libraries should have a similar function as well, in case you are using one. – hugomg May 31 '11 at 14:57
  • @missingno yes that's true, though (in my opinion) the jQuery "$.proxy()" is really weak. – Pointy May 31 '11 at 14:58
  • I am using jQuery. Is it preferred to use $.proxy() instead of JavaScript's bind()? I'm not too concerned with backwards compatibility, since I'm attempting to use HTML5 as much as possible. – Ishmael Smyrnow May 31 '11 at 15:07
  • @Ishmail Smyrnow you can use either one, really. One minor nuisance with using ".bind()" in jQuery code is that jQuery has its own ".bind()" function, which is completely different. On top of that, because the jQuery ".bind()" is used for registering event handlers, you end up with some crazy-looking code that mixes both meanings of ".bind()", and some people understandably don't like that :-) For many purposes, "$.proxy()" is perfectly OK. – Pointy May 31 '11 at 15:11
  • This is a matter of personal preference, but bind() has always left me with an uneasy feeling. It's purpose really boils down making it so people don't have to understand scoping in JavaScript. Makes it good for a short term solution, I suppose, but it seems counterproductive for actually understanding JS. – Matt May 31 '11 at 15:25
  • @Matt well maybe the best thing to do is learn how to implement "bind()" before you start using it heavily! – Pointy May 31 '11 at 15:27
  • @Pointy a very valid point! I'm not opposed to it's implementation, so much as it's philosophy :) When I was a JS novice and first encountered bind in a library and could only get my function calls to work when I used it, I just passed it off has some strange quirk/vodoo. When I learned about the scope chain, it was like a breath of fresh air, and I can't help but want others to experience the same epiphany :) – Matt May 31 '11 at 15:29
0

I don't know if i have understood completely your question. Would this suit your needs ?

var obj = new function() {
    var scope = this;

    this.fun1 = function() {
        return scope.fun2();
    }

    this.fun2 = function() {
        //do sth
    }
};
fusion
  • 1,257
  • 10
  • 15
0

This is caused by variable context and closure. "this" always refers to the current object. The event function is an object itself and "this" refers to that object. If you need to refer to the parent object you can use bind as described previously or you set the parent "this" to a variable and use that in your event function.

// Ish.Com namespace declaration
var Ish = Ish || {};
Ish.Com = Ish.Com || {};
// begin Ish.Com.View namespace
Ish.Com.View = new function() {
  var privateVariable, thisObj=this;
  this.publicFunction = function() {
    thisObj.publicFunction2()
  };
  this.publicFunction2 = function() { ... };
};
Bill
  • 21
  • 1
  • 4