Пища для ума
Задача чисто на интерес: можно ли написать функцию, которая проверяет является ли объект 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, время: 21:58. |