Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'll take

  $('p').text('Hello.')
over

  for (var p in document.getElementsByTagName('p')) { p.innerHTML = 'Hello.'; }
any day!


This enumeration is done the wrong way. You enumerate over a DOM node list which looks like an array, which includes enumerable properties like "length". This means that the variable "p" at some point will be "length" and "length".innerHTML = "..." will produce an error.

The proper way is:

for( var i=0, ps=document.getElementsByTagName('p'), len=ps.length; i < len; i++) {ps[i].innerHTML = 'Hello.';}


I'm a JS noob, but I though 'length' was not enumerable (i.e. its 'enumerable' property is set to 'false').

Edit: I think I missed what you said. You're saying it's "like" and array, but unlike arrays its `length` is enumerable. I'll leave my comment so other skeptics can benefit :)

Edit2: This is what I was referring to (read the 'Note' at the right side): http://bonsaiden.github.com/JavaScript-Garden/#object.forinl...


Looks like this is correct:

paras = document.getElementsByTagName('p') for (var para in paras) { console.log(para)} 0 1 ... 9 10 length item


That's ES3. You have no reason to choose that way anymore - ES5 loops work everywhere current, can be polyfilled into IE8, and don't require any boilerplate stuff.

var paragraphs = document.getElementsByTagName('p');

paragraphs.forEach(function(paragraph){paragraph.innerHTML = 'Hello.';})


This will not work - Check my solution below :)

document.getElementsByTagName returns a DOM Node List and it does not have forEach method according to the DOM spec. DOm Nodes, Elements and Node Lists and Node Maps do not follow the javascript spec (ECMAScript) hence do not share methdos and properties. A Dom Node List does not have the methods of the javascript array. That is because DOM Node List does not inherit from the Array.prototype, because it is not javascript - it has its own spec that exactly determines what methods and properties it should have. The implementation in the browser happens to be accessible through javascript but that does not mean that the DOM is part of javascript. That is why wrapper libraries like jQuery or other abstractions are necessary to make the DOM much more accessible from a JS perspective. BTW that is why many people confuse DOM with javascript and then get frustrated which is understandable.


Except #forEach is a method of Array, and getElementsByTagName does not return an Array but a NodeList. Which doesn't have any of Array's methods (it has a length, it can be indexed, and it has an alternative indexation method - #item — but it's not an array at all)


You're right. I wasn't sure earlier, as I was typing on a phone with no JS console.

but never mind:

Array.forEach.call(paragraphs, function(paragraph){paragraph.innerHTML = 'Hello.';})

will work fine.


Ah, thanks for the correction! I just wrote it out from memory, and it's been a while since I used Vanilla-JS DOM selectors ;)


Try this in a browser. On Webkit at least is also returns length and item:

for (var p in document.getElementsByTagName('p')) {console.log(p);}


The jquery version is easier to write, and less prone to error, but in the native version it's much more clear what's actually going on.


Also in the native version, you know you're only doing the work required. The jquery one will be doing a lot of extra useless inefficient grunt work to achieve nothing. Making it incredibly slow in comparison.


Premature optimization, and all that. It is trivial to get raw dom nodes out of jQuery, so you can easily use jQuery to begin with and replace any code with the full DOM API calls should it every become a performance issue.

This discussion is a bit like how assembly programmers used to defend not moving to a high level language long after the performance benefits were not worth it any more.


> This discussion is a bit like how assembly programmers used to defend not moving to a high level language long after the performance benefits were not worth it any more.

But we're not at that point in the web yet. The performance benefits are worth it. Just try out JQuery Mobile if you want to see what wasted CPU cycles can do.


It may be worth it for specific use cases, just like there are certainly still specific use cases where assembly shines.

The point is we're well past the point where grasping for the asm-equivalent from the start should be the default unless you happen to specifically target one of those niches.


Mobile isn't a niche.


That depends on the application.


It depends on what you're trying to do. Mostly, I try to write code that displays the same in every possible browser without special-casing or using confusing idioms. CPU cycles are cheap. A webpage that loads a little slow is a possible lost sale. A webpage that fails to load is a definite lost sale.


> It is trivial to get raw dom nodes out of jQuery, so you can easily use jQuery to begin with and replace any code with the full DOM API calls should it every become a performance issue.

That's still going to be a lot of work if the performance issues turn out to be many separate jQuery calls spread all over your code, which is not unlikely.


The jquery one will be doing a lot of extra useless inefficient grunt work

Such as?


"Useless" is subjective, but the jQuery object does a lot of extra work above the vanilla example.

$ isn't just a syntax layer on top of querySelectorAll. When you do $('p'), it first queries the DOM for everything that matches that selector, then it creates new jQuery objects to wrap each of the returned nodes as well as creating a jQuery object to contain them.

If all you're doing is setting the innerHTML of these objects, it's a non-trivial overhead.


It creates just one jQuery object to wrap the entire array of DOM nodes. Afterwards, .html() is essentially innerHTML [1], provided jQuery can use it directly (otherwise it has to create DOM nodes by itself).

[1] https://github.com/jquery/jquery/blob/master/src/manipulatio...


>but in the native version it's much more clear what's actually going on.

Yes, but it's also more probable that it won't go on at all (due to browser incompatibilities and such).


did you ever try to debug your pretty jquery karate?

ps. second example is not valid, in Vanilla JS you do it like this:

  document.getElementsByTagName('p').filter(function(el) {
    el.innerHTML = 'Hello.';
  });


The right way is this :)

Array.prototype.forEach.call(document.getElementsByTagName('p'), function(el) { el.innerHTML = 'Hello.'; });


I like how the end of that statement contains both a winking crooked-smile smiley next to black-eyed frown smiley.


Nope:

TypeError: document.getElementsByTagName("p").filter is not a function

Because you don't get an array, only something array-like.


And this discussion over how to write a trivial loop is why I stay far away from vanilla js unless performance absolutely forces me to optimize.


This is why I program with a code editor / interactive console that tells me these things as I'm typing :-)


I'll take $(node).remove() over node.parentNode.removeChild(node) any day.


innerHTML is an easy one, try setting an attribute -- you have to create a new attribute node, set its value and then add that to the element..


> you have to create a new attribute node, set its value and then add that to the element..

Erm... no you don't: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-F68F082


You should set the node property instead (e.g. standard textContent or innerText). It will work everywhere.


setAttribute()?


IE8 =(




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: