Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Отличить DOM-элемент от объекта (https://javascript.ru/forum/events/21200-otlichit-dom-ehlement-ot-obekta.html)

Octane 01.09.2011 04:12

Отличить DOM-элемент от объекта
 
Есть функция is, которая проверяет, удовлетворяет ли указанным параметрам DOM-элемент.
Ну например в jQuery:
$("body").is(document.body) //→ true


Пишу подобную функцию, но с возможностью указать объект с набором свойств для сравнения:
//сравниваем свойства
$("html").is({lang: "ru-RU"})

//сравниваем атрибуты
$("html").is('[lang="ru-RU"]')


И тут возникает проблема:
$("html").is({nodeType: 1, nodeName: "html"})

как отличить DOM-объект от обычного объекта?

Из-за IE простой проверкой node instanceof Node не обойтись, пришлось городить кучу условий:
//для IE<8
	function isNode(arg) {
		return Boolean(typeof arg == "object" && !(arg instanceof Object) && arg.nodeType);
	}


Есть ли способ сделать лучше?

devote 01.09.2011 07:51

function isNode( obj ) {
	var documentElement = ( obj ? obj.ownerDocument || obj : 0 ).documentElement;
	return documentElement ? documentElement.nodeName === "HTML" : false;
}

Octane 01.09.2011 12:56

На свойстве ownerDocument сломается:
function isNode( obj ) {
	var documentElement = ( obj ? obj.ownerDocument || obj : 0 ).documentElement;
	return documentElement ? documentElement.nodeName === "HTML" : false;
}

alert(isNode({ownerDocument: document})) // true


Я в надежде, что всплывёт какой-нибудь трюк, типа:
Array.isArray = function (obj) {
	return Object.prototype.toString.call(obj) == "[object Array]";
};

Kolyaj 01.09.2011 14:51

Можно воспользоваться тем, что IE не даёт выполнить стандартные js-методы в контексте не JScript-объектов.
alert([].slice.call(document.body))

Если вылетела ошибка, значит не обычный объект, для верности можно ещё проверить какой-нибудь tagName.

nikita.mmf 01.09.2011 15:13

Первое что пришло в голову поиграться с nodeType.
function isNode ( node ) {
	var nodeType = node && node.nodeType, isNode = true;
	if ( nodeType !== 1 || nodeType !== 9 ) { return !isNode; }
	try {
		delete node.nodeType;
		isNode = node.nodeType === nodeType;
		node.nodeType = nodeType;
	} catch ( e ) {}
	return isNode;
}

Еще интересным является, то что в IE, у dom элемента отсутствует конструктор
function isNode ( node ) {
	if ( !node ) return false;
	var type = Object.prototype.toString.call( node ).toLowerCase().slice(8,-1);
	return (type == "object" && node.constructor == null && typeof node.nodeType == "number") || (/^html/.test( type ) && !/collection$/.test( type ) || type == "global");
}

Octane 01.09.2011 15:34

delete только в IE7 для свойств DOM-элементов приведет к ошибке, а [].slice.call(node) — в IE7,8, тогда вариант без try-catch:
typeof obj == "object" && !(obj instanceof Object)
для этих браузеров привлекательнее мне кажется, под такое условие только null еще попадает.

Snipe 01.09.2011 16:59

А проверить наличие какой-нибудь функции, типа getElementById или cloneNode?
Или речь не только про теги?

Octane 01.09.2011 17:14

Да это понятно, что можно напроверять наличие кучи свойств и методов, но опять же, допустим напишем:

function isNode(obj) {
    return "hasChildNodes" in obj;
}


а кто-нибудь додумается сделать:
$(…).is({hasChildNodes: false})


дополнительными проверками конечно сведем вероятность неправильного результата к минимуму, но тему создавал в надежде, что найдем какое-нибудь интересное решение, как в случае с isArray :)


Часовой пояс GMT +3, время: 02:51.