views:

273

answers:

8

Being spoiled by jQuery I now include it into every project even if all I need from it is to call $("#div).hide() or $("#link").click() once.

I know that jQuery often takes care of cross-browser issues for you, but sometimes it is just a convenient wrapper for a native javascript methods.

So my question is which jQuery methods can be easily replaced by native javascript?

+3  A: 

The easiest way to find out is to just read the source code for the method you're curious about. It's very readable.

John Calsbeek
"very readable" apart from the most simple of methods you need a good grip of the underlying framework used in jQuery to understand what the methods actaully do and how it ensures cross-browser compatibility. I would think the average javascript writer would get lost.
Raynos
+2  A: 

(I liked the 'beating jQuery addiction')

I once posted a question and answered myself, regarding width() and height() and animation without jQuery. As you can see it's not as simple, but doable anyway.

mojuba
A: 

I don't know any jQuery-methods that can be replaced easily(and I don't think that there are any), if "easy" should mean that the jQuery-method is the same thing like the native method with another name.

For example see the hide()-documentation.
It does'nt simply set the display to "none", it also stores the current display-attribute(useful if you like to show it again later). Where could you store the display without jQuery? As a global variable?...better not.

Dr.Molle
-1 just because you don't have an idea how it could be done, don't assume that it's impossible to do it elegantly...
galambalazs
Give me 1 example of an "easy" translation, that will exactly do the thing the corresponding jQuery-method can do! I can comment every provided "easy" workaround here and tell you, why it's not the same. As long it's not the same, it's no easy translation, because you can't compare it. And if you try to translate it 1:1 you very fast come to a point that you will see that your easy translation is much more complicated. Keep in mind: we talk about "easy" and "cross-browser", not about "somehow". All the translations I see here so far only translate a part of the jQuery-functionality.
Dr.Molle
@Dr.Molle: Quite so. I'd say that it's a choice of (at most) two options: {easy,cross-browser,not-framework}. Trying to do yourself the things that jQ makes easy is a good learning (and humbling) experience. (usually terminated by "I wonder how I did not go crazy in the 2000s from the myriad browser quirks" in my case)
Piskvor
@galambalazs: Cross-browser JavaScript is rarely elegant or easy (esp. if it has to work in 9 year old browsers - do you code for Netscape Navigator 4.78 much? Yeah, didn't think so. Yet IE6 is still undead, despite being the same age.). If it weren't for the OP's requirement of "ease", there may be some possibilities (as seen in other answers - note that the snippets proffered are not exactly simple, or don't account for various browser braindeadnesses)
Piskvor
Well, you're beloved jQuery does a bunch of awful things inside which are not to be imitated, sometimes even jresig is unsure about how scope chain works bit.ly/9Ucqa6, the selector engine is one of the worst and "broken by design" bit.ly/c0ZliK, bit.ly/c3oiQK, bit.ly/99xQLS but keep on dreeming that your holy grail is 100% bulletproof... Netscape Navigator? Give me a break. :)
galambalazs
@galambalazs: I'm not saying jQ is bulletproof, I'm not even implying that everything in JS needs to be in jQ, not at all; I'm just saying that I don't have to worry *too much* about cross-browser inconsistencies, because there are useful, proven tools that abstract most of it away (a.k.a JS frameworks, e.g. jQuery). As for NN, exactly - yet some people still insist that I support an even *older* browser.
Piskvor
+10  A: 

Here are some examples I use instead of jQuery methods (if I don't use jQuery):

  • $(node).css(values):

    function css(node, style) {
      if(node && node.style) {
        for(var key in style) {
            node.style[key] = style[key];
        }
      }
    }
    
  • $(node).show(): jQuery is more sophisticated here as it also can set the display value to e.g. inline.

    function show(node) {
      if(node && node.style) {
        node.style.display = "block";
      }
    }
    
  • $(node).hide(): In addition, the jQuery method stores the previous display value.

    function hide(node) {
      if(node && node.style) {
        node.style.display = "none";
      }
    }
    
  • $(node).addClass(class)

    function addClass(node, cls) {
      if(node) {
        if(!node.className) {
            node.className = cls;
        }
        else if(node.className.indexOf(cls) == -1) {
            node.className = node.className + " " + cls;
        }
      }
    }
    
  • $(node).removeClass(class)

    function removeClass(node, cls) {
      if(node && node.className && node.className.indexOf(cls) >= 0) {
        var pattern = new RegExp('\\s*' + cls + '\\s*');
        node.className = node.className.replace(pattern, ' ');
      }
    }
    

These methods should be cross-browser compatible. The jQuery methods often provide more options, like removing multiple classes, or are more sophisticated.
It depends on your needs, whether you need the "advanced" functionality or not. Simpler methods might be sufficient. For example if I know that I will always have to hide div elements, this hide and show method is pretty ok.

Update:

Depending for which browser your are developing (e.g. making a Firefox extension) you can even get something close to jQuery's selector engine: document.querySelectorAll(selector)

Felix Kling
For `show()` and `hide()`, I prefer to add or remove a class ("hidden") from the element. That frees me from having to worry about the "display" value at all. The CSS for ".hidden" says "display: none", so when you take the "hidden" class away then it goes back to whatever it was before.
Pointy
Also your class add/remove routines are going to be confused by the class names "apple" and "big-apple". Better to build a regex by gluing "\b" on either side of the class name string, and (if your class names are potentially wacky) scrubbing it for regex metacharacters.
Pointy
@Pointy: Good points, thanks.
Felix Kling
There are a number of CSS attributes where this would fail, like [float](http://www.webdevthings.com/2008/05/ie-fun-fact-cssfloat-vs-stylefloat.html) or [opacity](http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html). Also, addClass/removeClass fail when one class is the prefix of another (though that is easy to fix) and show fails for visibility:hidden and for elements with a display of anything else than block.
Tgr
Your `show` method would be better to do: `node.style.display = "";` so even though it doesn't restore the previous value like jQuery, it would use the default display type for the element.
Nick Craver
+5  A: 

One of the biggest jQuery abuses out there has got to be creating a jQuery object solely for the purpose of getting a property of the element using .attr().

Perhaps the most common is getting the ID property using:

$(this).attr("id");

instead of

this.id;

There are plenty of properties that can be accessed in a cross-browser manner without using jQuery.

Or if I need access to the parent of an element in a handler, instead of:

$(this).parent()...

I'm more likely to wrap the parent directly with:

$(this.parentNode)...

If you can plan your HTML such that you don't have white space between your elements, you can easily use other DOM traversal methods in a cross-browser manner, like:

this.nextSibling
this.previousSibling
this.firstChild
this.lastChild
patrick dw
I would'nt agree. attr() will work only with attributes of an element, not with properties of a node, so it's more a equivalent to setAttribute/getAttribute. Furthermore it provides much more abilities than the native methods. The traversal-methods also have a different behaviour, for example a unified cross-browser-handling of (empty) textNodes.
Dr.Molle
@Dr.Molle - Regarding the traversal, I qualified it by saying *"If you can plan your HTML such that you don't have white space between your elements"*. This eliminates empty text node concerns. Regarding the comment that `.attr()` only works with attributes, I don't believe that's correct. I think it is a general purpose method that will grab either. Try setting an expando and using `.attr()` to get the value. It will retrieve it for you, whereas `getAttribute()` won't. Anyway, that doesn't change my point that you don't need jQuery to access many properties in a cross-browser way.
patrick dw
Its not a matter of spaces, the traversing-methods of jquery ignore textNodes, and that is good(usually you work with element-nodes). You may take a look at http://jsfiddle.net/doktormolle/FWwfs/ .So every time you work with the DOM-traversing-methods and -properties, you need a kind of filter-function which bypasses the textnodes, ...IMHO that it is'nt easy anymore. But of course I agree with you, that you should'nt use jQuery only to get some attributes or set the color of something.
Dr.Molle
I often see (and have even done this myself) using `$(this).val()` instead of `this.value`.
Peter Ajtai
@Peter - Yes, it has taken me a while to break the habit. IE6 has an issue with `<select>` lists where the `<option>` elements don't have a `value` property, but otherwise it's safe.
patrick dw
@Dr.Molle - Yes, I was thinking more in terms of making the native traversal cross-browser safe by removing white space so W3C compliant browsers give the same result as IE. But you're right, with jQuery traversal methods you skip text nodes altogether, which is usually what's desired.
patrick dw
A: 

For me, the $.each utility can generally be replaced with the for..in statement:

$.each (object, function () {
    // do something with this
}

vs

var current;
for (key in object) {
    current = object[key];
    // do something with current
}

The only additional feature $.each has is that it creates a new scope, allowing you to have more localised variables:

var someVar = 'original string';
$.each (object, function () {
    // do something with this
    var someVar = 'new string';
}
console.log(someVar); // 'original string'

You can, however, replicate this using for..in using self-executing functions:

var someVar = 'original string';
for (key in object) {
    (function() {
        var current = object[key],
            someVar = 'new string';
    })();
}
console.log(someVar); // 'original string'
lonesomeday
`$.each()` works on arrays as well, you should make this distinction since you should *not* use a `for...in` loop to **iterate** over an array.
Nick Craver
`for..in` fails in ugly ways when you muck with the `Object` prototype, whereas `$.each` does not.
Tgr
+1  A: 

.toggle() can be recreated relatively easily, especially the one with only 2 states (3+ states takes a little more work:

$(function() {    
    $(selector).each(function() {
        var counter = 1;
        $(this).click(function() {
            counter++ % 2 ? 
                (function() { $("div").html("one"); }());  // <== First function
                (function() { $("div").html("two"); }());  // <== Second function
        });
    });
});

Try it out with this jsFiddle


The above is equivalent to

$(selector).toggle(function() { ... }, function () { ... });
Peter Ajtai
Your example does'nt always do the expected, it's not equivalent: http://jsfiddle.net/doktormolle/gquKG/1/
Dr.Molle
@Dr. Molle - True. Edited. I was just trying to show how to use the conditional operator for a toggle.
Peter Ajtai
A: 

Here is a small Miniframework for you: JavaScript Miniframework

;)

shapeshifta