Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 12.03.2017, 03:42
Профессор
Отправить личное сообщение для exec Посмотреть профиль Найти все сообщения от exec
 
Регистрация: 21.01.2010
Сообщений: 1,022

Пища для ума
Задача чисто на интерес: можно ли написать функцию, которая проверяет является ли объект DOM-элементом, и которую невозможно обмануть, даже нарочно?

Проверять наличие tagName, nodeType не вариант - очень легко подать обычный объект: var fake = { tagName : "DIV" }

Такая функция:

function isDOMElement(target) {
	try {
		document.createDocumentFragment().appendChild(target.cloneNode());
	} catch (e) {
		return false;
	}
	return true;
}


выглядит неплохо, но её можно обмануть, подав такой объект: var fake = { cloneNode : function () { return document.createElement("DIV"); } }

Другой вариант:

function isDOMElement(target) {
	try {
		target.parentNode.insertBefore(target, target);
	} catch (e) {
		return false;
	}
	return true;
}


Её уже не провести, т.к. нативный insertBefore бросит исключение.
Но, к сожалению, не работает с новосозданными элементами, ведь у них нет parentNode:

isDOMElement( document.createElement("DIV") ); // false


Так как же быть?
Ответить с цитированием
  #2 (permalink)  
Старый 12.03.2017, 03:50
Профессор
Отправить личное сообщение для exec Посмотреть профиль Найти все сообщения от exec
 
Регистрация: 21.01.2010
Сообщений: 1,022

Пока что есть такое:

function isDOMElement(target) {
	try {
		target.parentNode.insertBefore(target, target);
	} catch (e) {
		try {
			var parent = document.createDocumentFragment();
			parent.appendChild(target);
		} catch (e) {
			return false;
		}
		parent.removeChild(target);
		return true;
	}
	return true;
}


var elem1 = document.createElement("A");
var elem2 = document.documentElement;
var elem3 = {};
alert( [isDOMElement(elem1), isDOMElement(elem2), isDOMElement(elem3)] ); // true,true,false


Можно ли как-то проще?
Ещё кроссбраузерность под вопросом, у меня в опере true, true, false

upd: разумеется, важно никак не менять структуру DOM, отсюда фокусы с insertBefore и appendChild/removeChild

Последний раз редактировалось exec, 12.03.2017 в 03:54.
Ответить с цитированием
  #3 (permalink)  
Старый 12.03.2017, 04:03
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,075

exec,
а так ?
function isDOMElement(target) {
  return target.ownerDocument == document
}
Ответить с цитированием
  #4 (permalink)  
Старый 12.03.2017, 04:11
Профессор
Отправить личное сообщение для exec Посмотреть профиль Найти все сообщения от exec
 
Регистрация: 21.01.2010
Сообщений: 1,022

function isDOMElement(target) {
  return target.ownerDocument == document
}

alert( isDOMElement({ ownerDocument : document }) );
Ответить с цитированием
  #5 (permalink)  
Старый 12.03.2017, 09:48
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

function isDOMElement(any) {
	return any instanceof HTMLElement ||
  			any instanceof HTMLDocument
}

console.assert(isDOMElement(document), 'document')
console.assert(isDOMElement(document.body), 'document.body')
console.assert(!isDOMElement({}), '{}')


Если делать
let proto = Object.create(HTMLElement.prototype)
// or
let proto2 = {__proto__: HTMLElement.prototype}

то данный объект по определению будет являться элементом, т.к. у него прототип элемента

У меня еще несколько вариантов есть, но пока их раскрывать не стану)
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #6 (permalink)  
Старый 12.03.2017, 17:53
Профессор
Отправить личное сообщение для exec Посмотреть профиль Найти все сообщения от exec
 
Регистрация: 21.01.2010
Сообщений: 1,022

Сообщение от nerv_ Посмотреть сообщение
то данный объект по определению будет являться элементом, т.к. у него прототип элемента
С ним нельзя будет работать как с DOM-элементом, например добавить его на страницу через appendChild. Так что это не DOM-элемент, а всего лишь объект с прототипом DOM-элемента.
Ответить с цитированием
  #7 (permalink)  
Старый 12.03.2017, 22:11
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

признаться, мне не понятно, в чем интерес данной задачи. Похоже на игру в интерпретатор: что верент этот код (и написан какой-нибудь треш).

Тем не менее, можно так поробовать
function isDOMElement(any) {
	return any instanceof Node && 
  			(any instanceof HTMLElement ||
  			 any instanceof HTMLDocument)
}

console.assert(isDOMElement(document), 'document')
console.assert(isDOMElement(document.body), 'document.body')
console.assert(isDOMElement(document.createElement('div')), 'document.createElement(\'div\')')
console.assert(!isDOMElement(Object.create(Node.prototype)), 'Object.create(Node.prototype)')
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[job] JS-разработчик (+Angular) на UI внутреннего проекта (для других разработчиков:) Anna-HR Работа 12 19.01.2015 13:50
виджет, только сторона клиента (JS, JQUery, работа с датами, масштабирование) eugen35 Работа 4 31.07.2014 09:50
Яндекс.Деньги организуют в Петербурге школу для веб-разработчиков LinaKurkova Работа 0 15.05.2014 22:41
drag-and-drop и position:fixed dotwatt Элементы интерфейса 5 05.12.2012 08:44
IDE для Java Script constant Библиотеки/Тулкиты/Фреймворки 0 27.09.2012 09:31