IE только ошибка JavaScript с getElementsByTagName - PullRequest
7 голосов
/ 27 января 2010

У меня есть следующий код, который работает в 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]);
                }
        }
    }
}

По сути дела, если он находит [test = 25] на странице, он преобразует его в ссылку, которая указывает на example.com/25

.

В IE я получаю следующую ошибку: Ожидаемый объект JScript в первой строке:

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

Эта ошибка возникает как в IE7, так и в IE8.

Любая помощь будет оценена.

Спасибо.

Ответы [ 3 ]

12 голосов
/ 27 января 2010

Недопустимо вызывать Array.prototype.slice для объекта NodeList, возвращаемого свойством childNodes (или различными другими методами DOM).

Обычно было бы неправильно вызывать Thing.prototype.method для чего-либо, кроме экземпляра Thing, однако браузеры традиционно разрешали - а стандарт ECMAScript Third Edition требует - особый случай для многих Array.prototype методов, чтобы они могут быть вызваны для любого объекта native-JavaScript, который достаточно похож на Array. Это означает, в частности, что они могут использоваться на объекте arguments, который выглядит как Array, но на самом деле это не так.

Однако NodeList и другие объекты коллекции в DOM не определены как собственные объекты JavaScript; им разрешено быть «объектами хоста», которые полностью реализуются браузером, а не языком. Все ставки на хост-объекты сняты ...

Возможность успешного применения функции слайса к хост-объекту зависит от реализации.

Так что Array.prototype.slice может не работать для NodeList, а в IE до версии 8 действительно не будет.

Если вы хотите сделать копию NodeList в виде обычного массива, вам придется сделать это длинным, но безопасным способом:

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)];

Кстати, вы можете сделать этот компоновщик немного проще, используя textnode.splitText, и я бы очень настороженно отнесся к использованию глобальных свойств RegExp, как если бы в одном из промежуточных вызовов они произвели неожиданную работу с регулярным выражением: потеряюсь Смотреть на предмет совпадения обычно лучше. См. этот вопрос , чтобы узнать о другой атаке, по сути, той же самой проблемы.

3 голосов
/ 27 января 2010

Я думаю, это потому, что getElementsByTagname возвращает список узлов, а не массив (хотя некоторые вещи, такие как оператор [], работают так, как будто они работают с массивами, они не совпадают)

Возможно, это можно решить менее сложным способом:

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
        }
    }
}
2 голосов
/ 27 января 2010

Попробуйте использовать это вместо:

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

В IE и прототипах / конструкторах есть какая-то особенность. Я не могу проверить прямо сейчас на Mac.

Подробнее здесь: Разница между Array.slice и Array (). Slice

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...