开发者

Javascript function pointers with Jquery causing domManip is not a function error

JQuery Version

jQuery JavaScript Library v1.4.4

Problem

The solution may be blatantly obvious, however I'm scratching my head.

The problem is while doing some code optimisation I came across a loop that called append on a jquery element a few times and it was a rather large loop. So it looked something like this:

var l开发者_JS百科ist_of_goodies = [1,2,3,...];
$.each(list_of_goodies, function(val) {
      $('div.toaddto').append(val);
      ...some more code...
      $('div.toaddto').append(otherval);
});

As you can see not really optimised so I tried to use function pointers so it looked something like this:

var list_of_goodies = [1,2,3,...];
var toaddtoAppend = $('div.toaddto').append;
$.each(list_of_goodies, function(val) {
      ... the other code...
      toaddtoAppend(val).append(otherval);
});

It may not seem like a huge optimisation, but it's a large list and this can save a lot of lookup time especially in the older IE's. This however causes an error.

The Error

this.domManip is not a function

Unfortunately this is from the minified jQuery, so there isn't much more info, it seems to happen within wrapInner() however.

Question

Is this a scope issue or a reference issue? I've tested it without using jQuery and the function pointer worked.

$.each or a for loop end up with the same results. Anyone know where I'm going wrong here? I know very little about how javascript handles function pointers, especially when they're supposed to be associated to an instance of something as opposed to just static, so forgive any ignorance here.

Browsers Tested In

  • Firefox 3.6
  • IE 6, 7 & 8
  • Chrome 9.0.something

Regardless of the browser the results are always the same, which seems to suggest it's not how the browser is handling the pointer that's causing it to break.

Test it Yourself

<html>
   <head>
     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
     <script type="text/javascript">   
         $(function(){
            var iterables = [];
            for (var i = 0; i < 1000; i++) iterables.push(i);
            var divAppend = $('#test').append;
            $.each(iterables, function(val) {
               divAppend(val);               
            });
         });       
      </script>
   </head>
   <body>
      <div id="test"></div>
   </body>
</html>

Thanks, dennmat


When you write var divAppend = $('#test').append, you're storing a reference to jQuery's standard append function.
It's equivalent to writing var divAppend = $.fn.append$('#test') isn't stored anywhere.

When you call divAppend as a normal function, its this is window, not a jQuery object.

You need to store a function that explicitly calls $('#test').append(...), or use divAppend.call($('#test'), val) to explicitly call append on the right object.


When you do this:

var toaddtoAppend = $('div.toaddto').append;

you do indeed get a reference to the "append" function, but you lose the relationship to the jQuery object. Thus when it's called later, there's no this reference for it to work on.

There's a method on Function instances available in newer browsers (and JavaScript engines) called "bind" that could do what you want here:

var toaddtoAppend = $('div.toaddto').append.bind($('div.toaddto'));

(I wouldn't write it that way of course, with the redundant call, but it's just an illustration.) That would give you a reference to a function that would call "append" with this being a reference to that jQuery object.


It is a scope issue, this will refer to window by the time you call the function. You could wrap the call to append in another function and store that for later use.

However, the real thing that you'll want to prevent is is not the lookup of a function but querying the DOM tree multiple times.

You can store the jQuery object with all the items in a variable and refer to that.

var toaddto = $('div.toaddto');
$.each(list_of_goodies, function(val) {
      toaddto.append(val);
      ...some more code...
      toaddto.append(otherval);
});

If you insist on storing the reference to the function you could do that as well:

var toaddto = $('div.toaddto');
var myappend = toaddto.append;
$.each(list_of_goodies, function(val) {
      myappend.call(tooaddto,  val);
      ...some more code... 
      myappend.call(tooaddto,  otherval);
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜