Як перевірити, чи об’єкт JavaScript об'єкт DOM?


248

Я намагаюся отримати:

document.createElement('div')  //=> true
{tagName: 'foobar something'}  //=> false

У своїх власних сценаріях я використовував це, оскільки мені ніколи не потрібен tagNameяк властивість:

if (!object.tagName) throw ...;

Тому для другого об'єкта я придумав таке швидке рішення - яке в основному працює. ;)

Проблема полягає в тому, що це залежить від браузерів, які застосовують властивості лише для читання, що не всі.

function isDOM(obj) {
  var tag = obj.tagName;
  try {
    obj.tagName = '';  // Read-only for DOM, should throw exception
    obj.tagName = tag; // Restore for normal objects
    return false;
  } catch (e) {
    return true;
  }
}

Чи є хороший замінник?


3
Мене непомітно цікавить, чи "Об'єкт DOM" повинен охоплювати не лише Елементи, а й усі Вузли (Текстові вузли, Атрибути тощо)? Усі відповіді та те, як ви поставили запитання, як правило, підказують, що це питання стосується саме Елементів ...
Майк гризун

Відповіді:


300

Це може зацікавити:

function isElement(obj) {
  try {
    //Using W3 DOM2 (works for FF, Opera and Chrome)
    return obj instanceof HTMLElement;
  }
  catch(e){
    //Browsers not supporting W3 DOM2 don't have HTMLElement and
    //an exception is thrown and we end up here. Testing some
    //properties that all elements have (works on IE7)
    return (typeof obj==="object") &&
      (obj.nodeType===1) && (typeof obj.style === "object") &&
      (typeof obj.ownerDocument ==="object");
  }
}

Це частина DOM, рівень 2 .

Оновлення 2 : Ось як я його реалізував у власній бібліотеці: (попередній код не працював у Chrome, тому що Node та HTMLElement - це функції замість очікуваного об'єкта. Цей код тестується в FF3, IE7, Chrome 1 та Opera 9).

//Returns true if it is a DOM node
function isNode(o){
  return (
    typeof Node === "object" ? o instanceof Node : 
    o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
  );
}

//Returns true if it is a DOM element    
function isElement(o){
  return (
    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
    o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
);
}

11
Варто зазначити, що це не працюватиме на елементах, що належать до інших вікон / рам. Набір качок - це рекомендований підхід
Енді Е

2
Можна обдурити це:function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
Кернель Джеймс

11
Факт WTF: Firefox 5 та попередні версії trueдля [] instanceof HTMLElement.
Rob W

6
Btw, HTMLElementзавжди є function, тому typeofвикине вас з колії і виконає другу частину заяви. Ви могли б спробувати , якщо ви хочете instanceof Object, тому що функція буде екземпляром Objectабо просто явно перевірити typeof === "function", тому що Nodeі HTMLElementобидва є носіями функції об'єкта.
Роланд

2
Коли ви телефонуєте isElement(0), він повертає 0, а не помилково ... Чому це так, і як я можу це запобігти?
Джессіка

68

Наведений нижче сумісний IE8, суперпростий код працює бездоганно.

Загальноприйнятий відповідь не може виявити всі типи елементів HTML. Наприклад, елементи SVG не підтримуються. На відміну від цього, ця відповідь працює як для HTML, так і для SVG.

Побачити це в дії тут: https://jsfiddle.net/eLuhbu6r/

function isElement(element) {
    return element instanceof Element || element instanceof HTMLDocument;  
}

3
'Елемент' не визначене на IE7
Dan

49
Я вважаю, що кожен, хто все ще використовує IE7, повинен витратити п’ять секунд на завантаження кращого браузера, а не накладати його на нас, щоб інвестувати дні чи тижні, працюючи навколо своєї відмови піти з часом.
мопсид

1
Я згоден з @mopsyd, але автор відповіді заявляє, що він працює в IE7, який, можливо, потрібно буде оновити заради коректності.
Лайош Мецарос

1
Оновлено, щоб сказати, що IE9. Я не впевнений, чи підтримує IE8.
Монарх Вадія

1
@MonarchWadia так, це підтримується в IE8. Але зауважте, що це не повертає істину для documentелемента (у всіх браузерах). якщо вам це потрібно, спробуйте:x instanceof Element || x instanceof HTMLDocument
S.Serpooshan

11

Усі рішення вище та нижче (включаючи моє рішення) страждають від можливості помилковості, особливо в IE - цілком можливо (пере) визначити деякі об'єкти / методи / властивості, щоб імітувати вузол DOM, що робить тест недійсним.

Тому зазвичай я використовую тестування стилю качки: я тестую спеціально для речей, які використовую. Наприклад, якщо я хочу клонувати вузол, я перевіряю його так:

if(typeof node == "object" && "nodeType" in node &&
   node.nodeType === 1 && node.cloneNode){
  // most probably this is a DOM node, we can clone it safely
  clonedNode = node.cloneNode(false);
}

В основному це невелика перевірка здоровості + прямий тест на метод (або властивість), який я планую використовувати.

Між іншим, тест, описаний вище, є хорошим тестом для DOM-вузлів у всіх браузерах. Але якщо ви хочете бути в безпеці, завжди перевіряйте наявність методів та властивостей та перевірте їх види.

EDIT: IE використовує об’єкти ActiveX для представлення вузлів, тому їх властивості не ведуть себе як справжній об’єкт JavaScript, наприклад:

console.log(typeof node.cloneNode);              // object
console.log(node.cloneNode instanceof Function); // false

при цьому він повинен повернути "функцію" і trueвідповідно. Єдиний спосіб перевірити методи перевірки, чи визначені вони.


"typeof document.body.cloneNode" повертає "об'єкт" в моєму IE
Dennis C

Це виглядає як гідна відповідь. Дивіться мою відповідь нижче, хоч, stackoverflow.com/a/36894871/1204556
Monarch Wadia

8

Ви можете спробувати додати його до справжнього вузла DOM ...

function isDom(obj)
{
    var elm = document.createElement('div');
    try
    {
        elm.appendChild(obj);
    }
    catch (e)
    {
        return false;
    }

    return true;
}

11
Це працює? Це все-таки рішення. Творчий в цьому.
Джастін Мейєр

3
+1 за творчість та впевненість, які це пропонує. Однак якщо вузол вже є частиною DOM, ви його просто видалили! Отже ... ця відповідь є неповною, не роблячи роботи над повторним додаванням елемента до DOM, якщо це необхідно.
svidgen

4
Я читаю це майже через 5 років, і думаю, що це одне з найкрутіших. Це просто потрібно вдосконалити. Ви можете спробувати додати клон вузла до відокремленого елемента, наприклад. Якщо це не об'єкт DOM. щось неодмінно піде не так. Але все-таки досить дороге рішення.
MaxArt

Або замість того , щоб намагатися приєднати клон елемента, просто намагається клонувати його повинно бути достатньо: obj.cloneNode(false). І не має побічних ефектів.
mauroc8

1
Це дійсно дорого і зайво складно. Дивіться мою відповідь нижче, stackoverflow.com/a/36894871/1204556
Monarch Wadia


6

Як щодо Ло-Даш_.isElement ?

$ npm install lodash.iselement

І в коді:

var isElement = require("lodash.iselement");
isElement(document.body);

1
Мені подобається це рішення. Це просто, і він працює в Edge та IE, навіть для елементів у окремих iframe, на відміну від більшості найвищих рішень тут.
Ілля Замарія

Ця відповідь корисна, хоча для запуску NPM модулів у браузері потрібен Webpack.
Едвін Пратт

5

Це з чудової бібліотеки JavaScript MooTools :

if (obj.nodeName){
    switch (obj.nodeType){
    case 1: return 'element';
    case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
    }
}

12
Цей код не стверджує, що об'єкт є елементом DOM; тільки, що це трохи схоже на одне. Будь-якому об'єкту може бути надано властивість nodeName та nodeType та задовольнити цей код.
thomasrutter

Ця відповідь не виявляє всіх типів елементів HTML. Наприклад, елементи SVG не підтримуються. Дивіться мою відповідь нижче.
Монарх Вадія

Дійсно не працює над усіма елементами, наприклад, SVG. Дивіться мою відповідь нижче, stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

З допомогою виявлення кореня знайдений тут , ми можемо визначити , наприклад , є чи сигнал тривоги є членом кореня об'єкта, який потім , ймовірно, буде вікно:

function isInAnyDOM(o) { 
  return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}

Щоб визначити, чи є об'єктом поточне вікно, ще простіше:

function isInCurrentDOM(o) { 
  return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}

Це здається менш дорогим, ніж рішення пробування / вловлювання у відкриваючій нитці.

Дон П


Я тестував це в останніх Chrome і FF, а також в IE11, і він працює скрізь, також для текстових вузлів та об’єктів, створених через, document.createElement()але також не вставлених у DOM. Дивовижно (: Дякую
Geradlus_RU

Це виглядає як гідна відповідь, хоча моє робить багато одних і тих же речей і менш складне. stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

стара нитка, але ось оновлена ​​можливість для користувачів ie8 та ff3.5 :

function isHTMLElement(o) {
    return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}

4

Я пропоную простий спосіб перевірити, чи змінна є елементом DOM

function isDomEntity(entity) {
  if(typeof entity  === 'object' && entity.nodeType !== undefined){
     return true;
  }
  else{
     return false;
  }
}

або як запропонував HTMLGuy :

const isDomEntity = entity => {
  return typeof entity   === 'object' && entity.nodeType !== undefined
}

1
Шлях занадто багатослівний. Порівняння вже поверне return typeof entity === 'object' && typeof entity.nodeType !== undefined;
буле

1
Дуже цікаво! Іноді, в залежності від типів, які ви маєте на своїх objects та / або poperties, це може бути дуже зручно! Tx, @ Роман
Педро Феррейра

3
var IsPlainObject = function ( obj ) { return obj instanceof Object && ! ( obj instanceof Function || obj.toString( ) !== '[object Object]' || obj.constructor.name !== 'Object' ); },
    IsDOMObject = function ( obj ) { return obj instanceof EventTarget; },
    IsDOMElement = function ( obj ) { return obj instanceof Node; },
    IsListObject = function ( obj ) { return obj instanceof Array || obj instanceof NodeList; },

// Насправді я скоріше за все не використовую ці вбудовані, але іноді добре мати ці ярлики для коду настройки


obj.constructor.name не працює в IE, оскільки в IE функції не мають властивості імені. Замініть obj.constructor! = Об’єкт.
mathheadinclouds

3

Це може бути корисно: isDOM

//-----------------------------------
// Determines if the @obj parameter is a DOM element
function isDOM (obj) {
    // DOM, Level2
    if ("HTMLElement" in window) {
        return (obj && obj instanceof HTMLElement);
    }
    // Older browsers
    return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);
}

У наведеному вище коді ми використовуємо оператор подвійного заперечення, щоб отримати булеве значення об'єкта, переданого як аргумент, таким чином ми гарантуємо, що кожне вираження, оцінене в умовному викладі, буде булевим, користуючись перевагою Оцінки короткого замикання , таким чином функцією повертає trueабоfalse


Що-небудь фальшиве повідомлення повинно коротко замикати вашу булеву. Наприклад, undefined && window.spam("should bork")ніколи не оцінює підроблену spamфункцію. Тож не !!потрібно, я не вірю. Що, чи можете ви надати краєзнавчий випадок, коли його використання має значення?
ruffin

Дякуємо за ваше висловлення. Я використав * !! * подвійне заперечення, щоб перетворити весь вираз на булеву величину, а не на правду чи хибність.
jherax

Правильно, але практичних причин для цього немає, я не думаю - дивіться тут . І звичайно не варто тут скористатися Короткорізним eval. Навіть якщо ви не купили !!аргумент " ніколи не потрібен" ( і якщо цього не зробити, мені цікаво, чому б ні ), ви можете відредагувати цей рядок return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);і змусити його працювати так само.
ruffin

Це я і зробив;) більш чистий і такий же ефект. спасибі.
jherax

2

Ви можете бачити, чи відповідний об'єкт або вузол повертає тип рядка.

typeof (array).innerHTML === "string" => false
typeof (object).innerHTML === "string" => false
typeof (number).innerHTML === "string" => false
typeof (text).innerHTML === "string" => false

//any DOM element will test as true
typeof (HTML object).innerHTML === "string" => true
typeof (document.createElement('anything')).innerHTML === "string" => true

3
typeof ({innerHTML: ""}).innerHTML === "string"
Qtax

ГОРЯЧЕ! Ця відповідь повинна бути переможцем гри. if (typeof obj.innerHTML! == 'string') // не елемент dom.
user3751385

1
Я спочатку відреагував на критику @Qtax та thomasrutter на попередню відповідь , але я починаю купувати її. Хоча я раніше не наштовхувався на собак, що б’ють таких качок, як це раніше, я можу побачити, як хтось не перевіряє, чи щось працює вузол notANode.innerHTML = "<b>Whoops</b>";, і пізніше, маючи цей код, передає свій забруднений об'єкт цьому коду. Оборонний код === кращий код, всі інші речі рівні, і це в кінцевому рахунку не є оборонним.
ruffin

2

Для тих, хто використовує Angular:

angular.isElement

https://docs.angularjs.org/api/ng/function/angular.isElement


Більш корисно включити код Angular : function isElement(node) { return !!(node && (node.nodeName || (node.prop && node.attr && node.find))); }Виглядає трохи як @ finpingvin's . Зауважте, що це визначає, " якщо посилання є елементом DOM (або загорнутим елементом jQuery). "
ruffin

2

Я думаю, що прототипування - не дуже вдале рішення, але, можливо, це найшвидше: визначте цей блок коду;

Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;

ніж перевірити об’єкти властивості isDomElement:

if(a.isDomElement){}

Я сподіваюся, що це допомагає.


1
1) змінювати об'єкти, якими ви не володієте, не рекомендується. 2) це не виявляє елементів, які не є частиною одного документа.
fregante

2

За даними мдн

Element- це найзагальніший базовий клас, з якого всі об'єкти мають у Documentспадок. У ньому є лише методи та властивості, загальні для всіх видів елементів.

Ми можемо реалізувати isElementза прототипом. Ось моя порада:

/**
 * @description detect if obj is an element
 * @param {*} obj
 * @returns {Boolean}
 * @example
 * see below
 */
function isElement(obj) {
  if (typeof obj !== 'object') {
    return false
  }
  let prototypeStr, prototype
  do {
    prototype = Object.getPrototypeOf(obj)
    // to work in iframe
    prototypeStr = Object.prototype.toString.call(prototype)
    // '[object Document]' is used to detect document
    if (
      prototypeStr === '[object Element]' ||
      prototypeStr === '[object Document]'
    ) {
      return true
    }
    obj = prototype
    // null is the terminal of object
  } while (prototype !== null)
  return false
}
console.log(isElement(document)) // true
console.log(isElement(document.documentElement)) // true
console.log(isElement(document.body)) // true
console.log(isElement(document.getElementsByTagName('svg')[0])) // true or false, decided by whether there is svg element
console.log(isElement(document.getElementsByTagName('svg'))) // false
console.log(isElement(document.createDocumentFragment())) // false


1

Я думаю, що те, що вам потрібно зробити, - це ретельно перевірити деякі властивості, які завжди будуть знаходитись у елементі dom, але їх поєднання, швидше за все, не буде в іншому об'єкті, як-от так:

var isDom = function (inp) {
    return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};

1

У Firefox ви можете використовувати instanceof Node. Це Nodeвизначено в DOM1 .

Але це не так просто в IE.

  1. Тільки "instanceof ActiveXObject" може сказати, що це рідний об'єкт.
  2. "typeof document.body.appendChild == 'object" "скажіть, що це може бути об'єкт DOM, але також може бути щось інше, що має таку ж функцію.

Ви можете переконатися, що це елемент DOM, лише скориставшись функцією DOM та перехопившись за будь-якого винятку. Однак це може мати побічний ефект (наприклад, змінити внутрішній стан об'єкта / продуктивність / витік пам'яті)


1

Можливо, це альтернатива? Тестовано в Opera 11, FireFox 6, Internet Explorer 8, Safari 5 та Google Chrome 16.

function isDOMNode(v) {
  if ( v===null ) return false;
  if ( typeof v!=='object' ) return false;
  if ( !('nodeName' in v) ) return false; 

  var nn = v.nodeName;
  try {
    // DOM node property nodeName is readonly.
    // Most browsers throws an error...
    v.nodeName = 'is readonly?';
  } catch (e) {
    // ... indicating v is a DOM node ...
    return true;
  }
  // ...but others silently ignore the attempt to set the nodeName.
  if ( v.nodeName===nn ) return true;
  // Property nodeName set (and reset) - v is not a DOM node.
  v.nodeName = nn;

  return false;
}

Функція не обдурить, наприклад, це

isDOMNode( {'nodeName':'fake'} ); // returns false

2
Хороша спроба, але обробка виключень - це занадто дорога вартість, якщо її можна уникнути. Також ES5 дозволяє визначати властивості лише для читання для об'єктів.
Енді Е

1

Це я зрозумів:

var isHTMLElement = (function () {
    if ("HTMLElement" in window) {
        // Voilà. Quick and easy. And reliable.
        return function (el) {return el instanceof HTMLElement;};
    } else if ((document.createElement("a")).constructor) {
        // We can access an element's constructor. So, this is not IE7
        var ElementConstructors = {}, nodeName;
        return function (el) {
            return el && typeof el.nodeName === "string" &&
                 (el instanceof ((nodeName = el.nodeName.toLowerCase()) in ElementConstructors 
                    ? ElementConstructors[nodeName] 
                    : (ElementConstructors[nodeName] = (document.createElement(nodeName)).constructor)))
        }
    } else {
        // Not that reliable, but we don't seem to have another choice. Probably IE7
        return function (el) {
            return typeof el === "object" && el.nodeType === 1 && typeof el.nodeName === "string";
        }
    }
})();

Для підвищення продуктивності я створив функцію самозванки, яка перевіряє можливості браузера лише один раз і відповідно призначає відповідну функцію.

Перший тест повинен працювати в більшості сучасних браузерів і тут вже йшлося. Він просто перевіряє, чи елемент є екземпляром HTMLElement. Дуже прямо.

Другий - найцікавіший. Це його основна функціональність:

return el instanceof (document.createElement(el.nodeName)).constructor

Він перевіряє, чи el є примірником конструктора, на який він претендує. Для цього нам потрібен доступ до провідника елемента. Ось чому ми тестуємо це в if-Statement. Наприклад, IE7 не вдається, оскільки (document.createElement("a")).constructorєundefined в IE7.

Проблема такого підходу полягає в тому, що document.createElementце насправді не найшвидша функція і може легко уповільнити вашу програму, якщо ви протестуєте багато елементів за допомогою неї. Щоб вирішити це, я вирішив кешувати конструктори. Об'єкт ElementConstructorsмає nodeNames як ключі з відповідними конструкторами як значення. Якщо конструктор уже кешований, він використовує його з кешу, інакше він створює Елемент, кешує його конструктор для подальшого доступу та потім тестує проти нього.

Третє випробування - неприємний запас. Він перевіряє, чи el є an object, має nodeTypeвластивість 1та string якnodeName . Звичайно, це не дуже надійно, але переважна більшість користувачів не повинні навіть відступати.

Це найнадійніший підхід, який я придумав, зберігаючи ефективність якнайбільше.


1

Перевірте, чи objуспадковується від Node .

if (obj instanceof Node){
    // obj is a DOM Object
}

Вузол - це базовий інтерфейс, від якого успадковуються HTMLElement та Text.


1

диференціювати необроблений js-об’єкт від HTMLElement

function isDOM (x){
     return /HTML/.test( {}.toString.call(x) );
 }

використання:

isDOM( {a:1} ) // false
isDOM( document.body ) // true

// АБО

Object.defineProperty(Object.prototype, "is",
    {
        value: function (x) {
            return {}.toString.call(this).indexOf(x) >= 0;
        }
    });

використання:

o={}; o.is("HTML") // false o=document.body; o.is("HTML") // true


0

ось фокус із використанням jQuery

var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")

$(obj).html() == undefined // true
$(element).html() == undefined // false

таким чином, поставивши його у функцію:

function isElement(obj){

   return (typeOf obj === 'object' && !($(obj).html() == undefined));

}

2
jQuery робить це всередині, elem.nodeType === 1чому б не зберегти накладні виклику та залежність jQuery, а ваша функція isElement сама зробить це?
Джозеф Леннокс

Це 2016 рік, просто скажіть «ні».
Thomas McCabe

0

Не забивати це чи щось, але для браузерів, сумісних з ES5, чому б не просто:

function isDOM(e) {
  return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}

Чи не буде працювати на TextNodes і не впевнений , що Shadow DOM або DocumentFragments і т.д. , але буде працювати майже на всіх HTML тегів елементів.


0

Це буде працювати майже для будь-якого браузера. (Тут немає різниці між елементами та вузлами)

function dom_element_check(element){
    if (typeof element.nodeType !== 'undefined'){
        return true;
    }
    return false;
}

Перш за все, вам не потрібно повертати true або повертати false, просто поверніть оператор if. По-друге, це повернеться справжнім для {nodeType: 1}
bluejayke

Я схильний використовувати надмірно багатослівний код (на цьому веб-сайті) для того, щоб зробити намір коду зрозумілішим;)
Zv_oDD

0

Абсолютний правильний метод, check check - це первинний код реального html елемента:

    (function (scope) {
        if (!scope.window) {//May not run in window scope
            return;
        }
        var HTMLElement = window.HTMLElement || window.Element|| function() {};

        var tempDiv = document.createElement("div");
        var isChildOf = function(target, parent) {

            if (!target) {
                return false;
            }
            if (parent == null) {
                parent = document.body;
            }
            if (target === parent) {
                return true;
            }
            var newParent = target.parentNode || target.parentElement;
            if (!newParent) {
                return false;
            }
            return isChildOf(newParent, parent);
        }
        /**
         * The dom helper
         */
        var Dom = {
            /**
             * Detect if target element is child element of parent
             * @param {} target The target html node
             * @param {} parent The the parent to check
             * @returns {} 
             */
            IsChildOf: function (target, parent) {
                return isChildOf(target, parent);
            },
            /**
             * Detect target is html element
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlElement: function (target) {
                if (!X.Dom.IsHtmlNode(target)) {
                    return false;
                }
                return target.nodeType === 1;
            },
            /**
             * Detect target is html node
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlNode:function(target) {
                if (target instanceof HTMLElement) {
                    return true;
                }
                if (target != null) {
                    if (isChildOf(target, document.documentElement)) {
                        return true;
                    }
                    try {
                        tempDiv.appendChild(target.cloneNode(false));
                        if (tempDiv.childNodes.length > 0) {
                            tempDiv.innerHTML = "";
                            return true;
                        }
                    } catch (e) {

                    }
                }
                return false;
            }
        };
        X.Dom = Dom;
    })(this);

Тест в IE 5


0

Кожен DOMElement.constructor повертає функцію HTML ... Element () або [Object HTML ... Element] так ...

function isDOM(getElem){
    if(getElem===null||typeof getElem==="undefined") return false;
    var c = getElem.constructor.toString();
    var html = c.search("HTML")!==-1;
    var element = c.search("Element")!==-1;
    return html&&element;
}

0

У мене є особливий спосіб зробити це, який ще не згадувався у відповідях.

Моє рішення засноване на чотирьох тестах. Якщо об'єкт передає всі чотири, то це елемент:

  1. Об'єкт недійсний.

  2. Об'єкт має метод, який називається "appendChild".

  3. Метод "appendChild" був успадкований від класу Node , і це не просто метод imposter (створене користувачем властивість з однаковим іменем).

  4. Об'єкт має тип вузла 1 (Елемент). Об'єктами, які успадковують методи з класу Node , завжди є Node , але не обов'язково Elements.

Питання: Як я можу перевірити, чи певна властивість успадковується і чи не є просто імпостером?

Відповідь: Простий тест, щоб перевірити, чи метод насправді успадкований від Node, - це спочатку перевірити, чи є у властивості тип "об'єкт" чи "функція". Далі перетворіть властивість у рядок і перевірте, чи містить результат текст "[Native Code]". Якщо результат виглядає приблизно так:

function appendChild(){
[Native Code]
}

Тоді метод був успадкований від об'єкта Node. Дивіться https://davidwalsh.name/detect-native-function

І нарешті, об’єднавши всі тести разом, рішення:

function ObjectIsElement(obj) {
    var IsElem = true;
    if (obj == null) {
        IsElem = false;
    } else if (typeof(obj.appendChild) != "object" && typeof(obj.appendChild) != "function") {
        //IE8 and below returns "object" when getting the type of a function, IE9+ returns "function"
        IsElem = false;
    } else if ((obj.appendChild + '').replace(/[\r\n\t\b\f\v\xC2\xA0\x00-\x1F\x7F-\x9F ]/ig, '').search(/\{\[NativeCode]}$/i) == -1) {
        IsElem = false;
    } else if (obj.nodeType != 1) {
        IsElem = false;
    }
    return IsElem;
}

0
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

Це перевірятиметься, навіть якщо це елемент jQuery або JavaScript DOM


0

Єдиний спосіб гарантувати те, що ви перевіряєте фактичний HTMLEement, а не лише об’єкт із тими ж властивостями, що і HTML-елемент, - це визначити, чи він успадковується від Node, оскільки неможливо створити новий Node () в JavaScript. (якщо тільки функція нативного вузла не буде перезаписана, але тоді вам не пощастить). Так:

function isHTML(obj) {
    return obj instanceof Node;
}

console.log(
  isHTML(test),
  isHTML(ok),
  isHTML(p),
  isHTML(o),
  isHTML({
    constructor: {
      name: "HTML"
    }
  }),
  isHTML({
    __proto__: {
      __proto__: {
        __proto__: {
          __proto__: {
            constructor: {
              constructor: { 
                name: "Function"
                
              },
              name: "Node"
            }
          }
        }
      }
    }
  }),
)
<div id=test></div>
<blockquote id="ok"></blockquote>
<p id=p></p>
<br id=o>
<!--think of anything else you want--!>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.