IE only javascript error with getElementsByTagName

I have the following code that works in FF / Chrome

var stack = [Array.prototype.slice.call(document.getElementsByTagName("body")[0].childNodes)], nodes, node, parent, text, offset; while (stack.length) { nodes = stack.pop(); for (var i=0, n=nodes.length; i<n; ++i) { node = nodes[i]; switch (node.nodeType) { case Node.ELEMENT_NODE: if (node.nodeName.toUpperCase() !== "SCRIPT") { stack.push(Array.prototype.slice.call(node.childNodes)); } break; case Node.TEXT_NODE: text = node.nodeValue; offset = text.indexOf("[test="); if (offset >= 0 && text.substr(offset).match(/^(\[test=(\d+)\])/)) { parent = node.parentNode; var before = document.createTextNode(text.substr(0, offset)); link = document.createElement("a"), after = document.createTextNode(text.substr(offset + RegExp.$1.length)); link.appendChild(document.createTextNode(text.substr(offset, RegExp.$1.length))); link.setAttribute("href", "http://example.com/" + RegExp.$2); parent.insertBefore(after, node); parent.insertBefore(link, after); parent.insertBefore(before, link); parent.removeChild(node); stack.push([after]); } } } } 

Basically, what does he do if he finds [test = 25] on the page, he will convert it to a link that points to example.com/25

In IE, I get the following error: JScript object expected in the first line:

 var stack = [Array.prototype.slice.call(document.getElementsByTagName("body")[0].childNodes)], nodes, node, parent, text, offset; 

This error occurs in both IE7 and IE8.

Any help would be appreciated.

Thanks.

+7
javascript internet-explorer
source share
3 answers

You cannot call Array.prototype.slice on the NodeList returned by the childNodes property (or various other DOM methods).

It would usually not be legal to call Thing.prototype.method on anything other than a Thing instance, however browsers are traditionally allowed - and the ECMAScript Third Edition standard requires - a special case for many Array.prototype methods, so that they can be called on any object native-JavaScript, which is quite similar to Array . This means that they can be used for an arguments object that looks like an Array , but in fact it is not.

However, NodeList and other collection objects in the DOM are not defined as native JavaScript objects; they are allowed to be "host objects" that are fully implemented by the browser, not the language. All bids are disabled for host objects ...

Whether the slice function can be successfully applied to a host object is implementation dependent.

So Array.prototype.slice may not work for NodeList, but in IE prior to version 8 it is not.

If you want to create a copy of NodeList with a simple array, you have to do it in a long but safe way:

 Array.fromSequence= function(seq) { var arr= new Array(seq.length); for (var i= seq.length; i-->0;) if (i in seq) arr[i]= seq[i]; return arr; }; var stack = [Array.fromSequence(document.body.childNodes)]; 

By the way, you can make this linker a little easier with textnode.splitText , and I would be very wary of using the global RegExp properties, as if any unexpected work in the regular expression occurred in one of the intermediate calls would be lost. It’s usually better to look at an object of coincidence. See this question for another attack on the same issue.

+12
source share

I think this is because getElementsByTagname returns a nodelist - not an array (although some things, like the [] operator, work as if they work with arrays, they don't match)

Perhaps this can be solved in a less complicated way:

 var els = document.body.getElementsByTagName("*"); for (var i=0, numEls=els.length, el; i<numEls; i++){ el = els.item(i); el.normalize(); for (var j=0, chs = el.childNodes, numChs=chs.length, ch; j<numChs; j++){ ch = chs.item(j); if (ch.nodeType==Node.TEXT_NODE){ //you code for replacing text with link goes here //ps i suggest using ch.data instead of ch.nodeValue } } } 
+3
source share

Try using this instead:

 var stack = [Array().slice.call(document.getElementsByTagName("body")[0].childNodes)] 

There is some fun with IE and prototype / constructors. I can’t check right now on mac.

Read more here: The difference between Array.slice and Array (). slice

+2
source share

All Articles