2

I'm wondering whether lazily doing $( something ) without first checking whether something is already a jQuery instance has any performance downsides?

The use case I'm thinking of is a function like the following:

function foo( element ){
  var $element = $( element );
  // do something with $element...
}

If you pass a jQuery instance to that function, are you re-wrapping a jQuery instance with another jQuery instance? And does that have any performance implications (say, over many iterations)?

foo( $( "#somediv" ) );

Looking at the source code (v 2.1.4 as of this question), we see jQuery.fn.init checking the selector that's passed to it, and if it's not a string, a DOM element or a function, then we just pass it through jQuery.makeArray and return the result.

So there doesn't appear to be any explicit checking within the jQuery "constructor" that short-circuits if the selector is already a jQuery instance. But does it really matter?

makeArray uses merge and/or push, so there's a bit of extra processing, but is it significant?

Tom Auger
  • 19,421
  • 22
  • 81
  • 104
  • If you're uncertain, I'd say you can check if it's already a jQuery object using `instanceof jQuery` – Claudio Redi Jun 10 '15 at 18:09
  • Your question isn't precise enough but `$(jqueryObject)` goes through [`makeArray`](https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/src/core.js#L300) which is far from being just a simple test. I personally try to avoid such a case when performances may matter. – Denys Séguret Jun 10 '15 at 18:09

1 Answers1

3

All right, since I seem to never be able to walk away from a Yak that needs shaving, here's the JSPerf test, which seems to suggest that checking and short-circuiting instead of (accidentally) re-wrapping a jQuery instance can improve performance by up to 30%. In my books, that's significant enough to warrant the uglier code.

Here are the two tests:

function noCheck(element) {
  var $element = $(element);

  $element.css("color", "red");
}

noCheck($("#somediv"));

function shortCircuit(element) {
  var $element = element instanceof jQuery ? element : $(element);

  $element.css("color", "red");
}

shortCircuit($("#somediv"));

According to JSPerf, noCheck performs 30% slower than shortCircuit

Play around with this code in JSFiddle.

I'm not going to accept my answer for a while to encourage additional perspectives / tests, etc.

Tom Auger
  • 19,421
  • 22
  • 81
  • 104
  • Cool test, but I have a question. If jQuery function really is using makeArray for everything that is "not a string, a DOM element or a function," then how come `$($('body')) instanceof Array` returns false but `$.makeArray($('body')) instanceof Array` returns true? I'm just curious and sorry if I'm missing something important. – Shashank Jun 10 '15 at 18:24
  • @Shashank sounds like that should be another SE question! I got bogged down once I got into `makeArray()`, hence the reason I posted the original question! :) – Tom Auger Jun 10 '15 at 18:39
  • I was kind of hoping you could answer seeing as how you've already looked at the jquery source, and my question is based on the premise that what you said is true (I haven't perused the source myself), but nvm. I'll add this task to my callback queue. – Shashank Jun 10 '15 at 18:45
  • 30% isn't enough to optimize for with >90% of webapps. And the reason jQuery doesn't do it by default is probably so a "broken" jquery object is replaced with a fresh one. – DanielST Jun 10 '15 at 19:05
  • @slicedtoad that's an interesting perspective. What's a "broken" jQuery object, how does it get that way and how does re-wrapping it fix it (based on the source code)? – Tom Auger Jun 11 '15 at 13:36
  • @TomAuger I was just guessing, but I tested it and it works. I'll add an actual answer. – DanielST Jun 11 '15 at 13:43
  • @TomAuger, nvm. It fixes some things, like if you do `$().prevObject = 3` wrapping it will remove `prevObject` completely. But it won't recreate `$().selector`, so I don't think it's really meant to be used to unbreak jquery objects. – DanielST Jun 11 '15 at 13:59