Пища для ума
Задача чисто на интерес: можно ли написать функцию, которая проверяет является ли объект 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 Так как же быть? |
Пока что есть такое:
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,
а так ? function isDOMElement(target) { return target.ownerDocument == document } |
function isDOMElement(target) { return target.ownerDocument == document } alert( isDOMElement({ ownerDocument : document }) ); |
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} то данный объект по определению будет являться элементом, т.к. у него прототип элемента У меня еще несколько вариантов есть, но пока их раскрывать не стану) |
Цитата:
|
признаться, мне не понятно, в чем интерес данной задачи. Похоже на игру в интерпретатор: что верент этот код (и написан какой-нибудь треш).
Тем не менее, можно так поробовать 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)') |
Часовой пояс GMT +3, время: 09:35. |