В чем здесь разница между Chrome и Firefox?

Я использую рекурсивную функцию, основанную на for(.. in..) и hasOwnProperty для клонирования объектов, которая отлично работает в IE и FF... но не в Chrome.

При переборе членов объекта с использованием for(... in...) Firefox и Chrome дают разные результаты для hasOwnProperty, если объект является объектом DOM.

Ввод следующего в консоль Chrome по сравнению с консолью в Firebug (FF) дает разные результаты:

var t = document.createElement("table");
var tr = t.insertRow(-1);
for(var p in tr) if(tr.hasOwnProperty(p)) console.log(p);

Вывод Firefox:

конструктор
addEventListener

Вывод Chrome:

clientLeft
scrollHeight
firstElementChild
offsetParent
ch
offsetWidth
isContentEditable
hidden
previousElementSibling
parentElement
localName
children
ownerDocument< br> nodeValue
lastElementChild
rowIndex
offsetLeft
tagName
className
prefix
innerHTML
previousSibling
namespaceURI
id
childElementCount
innerText
scrollLeft
clientHeight
align
textContent
nextSibling
scrollWidth
offsetHeight
chOff
clientWidth
nodeName
стиль
lang< br> scrollTop
offsetTop
childNodes
baseURI
nextElementSibling
vAlign
sectionRowIndex
classList
title
firstChild
атрибуты
набор данных
externalText
ячейки
parentNode
clientTop
tabIndex
contentEditable
externalHTML
dir
lastChild
bgColor
nodeType
проверка орфографии
перетаскиваемый

Все дополнительные свойства, помеченные как истинные для hasOwnProeperty, вызывают отказ «бесконечно/достаточно для сбоя» в моем коде. Есть ли способ определить, является ли свойство встроенным свойством объекта DOM? Или другое решение..


person Mattias    schedule 16.03.2011    source источник
comment
+1 кажется интересным .. Гуру JS - есть рекомендации?   -  person jrharshath    schedule 16.03.2011


Ответы (3)


Самое простое решение — проверить метод .cloneNode и использовать его, если он существует.

Это означает, что ваш метод клонирования будет проверять любые узлы DOM и использовать для них предопределенный метод DOM. Это должно полностью избежать вашей проблемы.

Что касается вашей реальной проблемы. Кажется, Chrome и Firefox расходятся во мнениях относительно того, что относится к прототипу, а что к объекту для HTMLTableRowElement (и любого другого элемента).

Сравните console.dir(HTMLTableRowElement) в Firefox и Chrome.

В firefox все эти свойства живут в прототипе HTMLTableRowElement. В то время как прототип хрома имеет только несколько методов. (delecteCell и insertCell).

Нигде в спецификации DOM не говорится, должны ли свойства HTMLElements определяться в прототипе или в конкретном объекте, поэтому вам не следует полагаться на это.

В любом случае используйте .cloneNode, потому что это собственный метод и, следовательно, лучше/быстрее, чем все, что вы можете написать на JavaScript.

Псевдо-реализация Chrome:

function HTMLTableRowElement() {
    ...
    this.nextSibling = ...;
    this.nodeName = ...;
    this.nodeType = ...;
    ...
}

HTMLTableRowElement.prototype.deleteCell = function() { ... };
HTMLTableRowElement.prototype.insertCell = function() { ... };

Псевдо-реализация Firefox

function HTMLTableRowElement() {
    ...
}

HTMLTableRowElement.prototype.nextSibling = ...;
HTMLTableRowElement.prototype.nodeName = ...;
HTMLTableRowElement.prototype.nodeType = ...;
...
HTMLTableRowElement.prototype.deleteCell = function() { ... };
HTMLTableRowElement.prototype.insertCell = function() { ... };
person Raynos    schedule 16.03.2011

Я думаю, что @Raynos предлагает хорошее решение в своем ответе. Что касается почему вещи такие разные, я подозреваю, что основная проблема заключается в том, что элемент DOM не является объектом JavaScript, то есть он никоим образом не наследуется от класса "Object" JavaScript. Элементы DOM предоставляются средой выполнения и имеют поведение и семантику, которые (обычно) имеют смысл для кода JavaScript, но на самом деле они не являются объектами JavaScript внутри. Таким образом, для меня несколько удивительно, что «hasOwnProperty» вообще доступен для вызова.

person Community    schedule 16.03.2011
comment
@Pointy Я не согласен. Это объекты JavaScript. Они наследуются от Object и наследуются от HTMLTableRowElement - person Raynos; 16.03.2011
comment
@Raynos, я не уверен, что это правда. Вокруг них могут быть обертки объектов JavaScript, и я полагаю, что некоторые реализации JavaScript-в-браузере могут фактически реализовывать их таким образом, но я не вижу причин для того, чтобы это обязательно имело место. Конечно, в других средах JavaScript объекты, помещаемые средой выполнения в глобальное пространство имен, не являются объектами JavaScript, даже если они доступны из кода JavaScript. - person Pointy; 16.03.2011
comment
@Pointy Afaik, все объекты браузера наследуются от JavaScript Object.prototype. Я бы удивился, если бы было иначе. Например, цепочка прототипов для объекта document такова: document --> HTMLDocument.prototype --> Document.prototype --> Node.prototype --> Object.prototype --> null - person Šime Vidas; 16.03.2011
comment
@Правильно. Это не просто объекты JavaScript. Я думаю, что существует явно надмножество объектов JavaScript, но они все еще существуют, как и все остальное. Например, вы не можете напрямую вызывать конструкторы их прототипов, и они делают другие забавные вещи. - person Raynos; 16.03.2011
comment
@Raynos @Šime Vidas Я предлагаю вам это jsfiddle попробовать в Internet Explorer, который не предоставляет hasOwnProperty API для элементов DOM. - person Pointy; 16.03.2011
comment
Опять же, они могут быть объектами JavaScript, но я не знаю ни одной спецификации, которая настаивала бы на том, чтобы элементы DOM вели себя точно так же, как если бы они были. - person Pointy; 16.03.2011
comment
@ Pointy, ты прав. Но это всего лишь случай, когда IE делает это неправильно. Попробуйте IE9. (document.createElement("tr") instanceof Object) === false в IE8. Я лично вижу это, поскольку объекты/узел DOM должны быть объектами JavaScript, и что IE ошибается, а не является не объектами javascript. - person Raynos; 16.03.2011
comment
@Raynos Хорошо, я разделяю ваше желание, чтобы IE перестал быть сложным :-) Я считаю, что среды выполнения JavaScript могут делать глобальные символы (например, окна) доступными разными способами, и они не должны вести себя как объекты JavaScript. хорошо, если они это сделают, но я не знаю никаких спецификаций по этому поводу (а вы?). Например, можно открыть объекты Java для JavaScript, работающего в Rhino, и они определенно не ведут себя (намного) как объекты JavaScript. - person Pointy; 16.03.2011
comment
Объекты @Pointy DOM наследуют свойство hasOwnProperty от Object.prototype во всех текущих браузерах (да, я использую тот факт, что IE9 вышел вчера). Предыдущие версии IE делали свое дело, современные браузеры делают это правильно. Afaik, стандарт ECMAScript не требует, чтобы хост-объекты наследовались от Object.prototype, но производители браузеров реализовали его таким образом, и это хорошо. Однако вы правы в том, что объекты DOM не являются объектами JavaScript. - person Šime Vidas; 16.03.2011
comment
@SimeVidas Мне нравится фраза, что все современные браузеры теперь я могу притвориться, что IE8 больше не существует. Отказ от поддержки IE8 будет замечательным. - person Raynos; 16.03.2011

Самый простой способ определить, является ли объект объектом DOM, — это проверить, имеет ли этот объект свойства nodeName, nodeValue или nodeType.

if ( tr.nodeType > 0 ) {
    // tr is a DOM object
} else {
    // tr is not a DOM object
}

Все объекты DOM реализуют интерфейс узла. и, следовательно, обладают указанными выше свойствами.

person Šime Vidas    schedule 16.03.2011
comment
stackoverflow.com/questions/384286/ - person CAFxX; 16.03.2011
comment
@CAF Я считаю, что мой метод достаточно хорош ... он, безусловно, самый простой. Ведущий ответ на этот вопрос - излишний имхо. - person Šime Vidas; 17.03.2011