"this" does not solve, as expected, when I apply jQuery dom manipulation methods to the name?

I managed to avoid using the namespace in most of my javascript developers today, but I am starting to see the light by reading useful articles such as this

I follow the Maeagers technique found here to create my namespace as shown below -

var newAndImproved = { //div to put loaded content into targetDiv: "", //loads the initial content based on an anchor tag having a class named 'chosen' loadInitialPage: function() { var chosenLink = $("#subnavigation a.chosen"); newAndImproved.loadPartial(chosenLink); }, loadPartial: function(clickedLink) { var theUrlToLoad = $(clickedLink).attr("href"); $(newAndImproved.targetDiv).load(theUrlToLoad, function(response, status, xhr) { if (status == "error") { var msg = "Sorry but there was an error: "; $(targetDiv).html(msg); } }); }, removeClassFromSubNav: function() { $("#subnavigation a").removeClass('chosen'); }, addChosenClassToNav: function(chosenLink) { $(chosenLink).addClass('chosen'); }, bindMethodsToNavigation: function() { $("#subnavigation a").bind('click', function(event) { var chosenLink = event.target; newAndImproved.removeClassFromSubNav(); newAndImproved.loadPartial(chosenLink); newAndImproved.addChosenClassToNav(chosenLink); return false; }); } }; 

I called this namespace the following:

 $(document).ready(function() { newAndImproved.targetDiv = $("#subcontent"); newAndImproved.loadInitialPage(); newAndImproved.bindMethodsToNavigation(); }); 

I am sure that you have noticed that I am referring to the namespace within myself, and not just to using 'this'. I assume this is not true. But when I use 'this', the required part will not work.

Oddly, the loadInitialPage method will work when using 'this'.

Any idea what I'm doing wrong?

Thanks in advance.

+4
source share
2 answers

You need to use that . this gets overridden in new areas, including the anonymous function you are binding.

Consider this code:

 function say(x){ alert(x); } var myscope = { label : "myscope (toplevel)", func1 : function() { say("enter func1"); var label = "inner func1"; say(" this.label: " + this.label); say(" label: " + label); }, func2 : function() { var label = "inner func2"; say("enter func2"); this.func1(); } }; myscope.func2(); 

If you run this, it will behave nicely, and the links to this.xxx will succeed as you would like. However, if you add func3 as follows:

  func3 : function() { setTimeout( function(){ var label = "anonymous func"; say("enter anon func"); this.func1(); }, 2); } 

... it will not work as you might imagine. Since an anonymous function is defined without an explicit scope, this inside it refers to a top-level object, window . And there is no func1 as a child of the window (without a top-level object named func1 ).

For the same reason, this in your anon function, which you use when calling bind() , will not work. In this case, you can directly refer to the "namespace" object, or you can use closure (some call it the " that trick)):

  bindMethodsToNavigation: function() { var that = this; $("#subnavigation a").bind('click', function(event) { var chosenLink = event.target; that.removeClassFromSubNav(); that.loadPartial(chosenLink); that.addChosenClassToNav(chosenLink); return false; }); } 

this in the field of bindMethodsToNavigation refers to newAndImproved . this in an anonymous function will refer to window . Using closure allows you to reference what you want. (editorial comment: I personally find that name pretty and completely useless. I like to use shortened names, in your case there might be something like nai to refer to newAndImproved )

By the way, you can also do this:

  clickHandler : function(event) { var chosenLink = event.target; this.removeClassFromSubNav(); this.loadPartial(chosenLink); this.addChosenClassToNav(chosenLink); return false; }, bindMethodsToNavigation: function() { $("#subnavigation a").bind('click', clickHandler); }, 

... and if they are both members of the newAndImproved object, then this inside clickHandler will be resolved to the newAndImproved object. The key point here is that clickHandler not an anonymous top-level function; it belongs to newAndImproved , and when this used inside it, it resolves accordingly. Moreover, you can simply refuse to use this inside clickHandler ; this is not true, but it is not necessary. Some people like to add them for emphasis to those who can read the code later.


EDIT

Another point about this is the decision to use anonymous functions or named functions as event handlers ... Anon functions are so convenient and easy, and everyone uses them. What I find is that in Firebug or IE Javascript Debugger, when I look at the stack trace, I get a list of anonymous functions, and it's hard to understand what a function chain is. Especially with AJAX and async handlers that fire in response to user interface events and so on. To provide additional visibility during debugging, I sometimes use named functions (we put them in namespaces), and in a callstack several named fns will be shown along with interspersed several anon fns. Sometimes it helps. However, this is a small thing.

+6
source

I don't see the need for namespaces at all. This looks like a very specific implementation (rather than a reusable class). Wouldn't that be much simpler:

 $(document).ready(function() { var targetDiv = $("#subcontent"), loadInitialPage = function() { ... }, loadPartial = function(clickedLink) { ... }, removeClassFromSubNav: function() { ... }, addChosenClassToNav = function(chosenLink) { ... }, bindMethodsToNavigation = function() { ... }; loadInitialPage(); bindMethodsToNavigation(); }); 

Simplification, because now you can refer to all functions without a namespace. No need for this. or namespacename. .

Why separate name / function space declarations from document.ready material?

change
You must read this. These are more than a few lines, but very readable and very useful.

change
It is good to put a lot of things in document.ready , because it is only done once.

+1
source

All Articles