lodash 的 isElement 等价于纯 JS
lodash's isElement equivalent in pure JS
现在我正在使用 isElement
by lodash 检查一个元素是否 DOM 可能。我想摆脱这个库,所以我正在寻找这个功能的纯 JS 实现。
我正在使用它,但我不知道它是否是正确的实现以及我是否忽略了任何边缘情况:
const isDOMElement = el => el instanceof HTMLElement
更新
我已经测试过(codepen link) the four proposed implementation, in all cases is working as expected, maybe the one proposed by @cesare covers most of the cases, but also the one proposed by @peter-seliger is clever and work with an "outside of the BOX" thinking. Finally, both @David Thomas 并且我第一次使用的那个适用于大多数情况。
总而言之,我认为,正如 David Thomas 指出的那样 It's just a matter of preference
。
P.S:测试用到的标签摘自MDN的HTML elements reference
P.S2:不确定如何进行以及接受什么答案。 cesare 和 peter 都有一个很好的观点
从库源代码看实现:
这是 lodash
实用程序:
function isElement(value) {
return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value)
}
基本上 isObjectLike
它检查传递的值是一个非 null
对象(因为 null 是 js 中的一个对象)并且 !isPlainObject
它不是一个普通对象(因为它可能是一个带有 "nodeType": 1 条目的对象,并且因为 HTMLElement 实例具有嵌套原型。
isPlainObject
实用程序是这样的:
function isPlainObject(value) {
if (!isObjectLike(value) || getTag(value) != '[object Object]') {
return false
}
if (Object.getPrototypeOf(value) === null) {
return true
}
let proto = value
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
如您所见,第一次检查是多余的,因为它再次检查 isObjectLike
,但我认为主要的警告是它不涵盖其他对象情况,因为例如“数组”是对象也因此他们通过了检查:
const arr = [1, 2]; // array
arr.nodeType = 1; // add nodeType property to the array object
console.log(isElement(arr)); // true Lodash
自己试一下。
我认为检查对象是否具有继承的 nodeType
属性 更安全:
const _isElement = (node) =>
typeof node === 'object' &&
node !== null &&
!node.hasOwnProperty('nodeType') &&
node.nodeType &&
node.nodeType === 1
const el = document.createElement('h1'); // node
const arr = [1, 2]; // array
arr.nodeType = 1; // add nodeType property to the array object
console.log(isElement(arr)); // true Lodash
console.log(isElement(el)); // true Lodash
console.log(_isElement(arr)) // false
console.log(_isElement(el)) // true
无论如何,我更喜欢使用你的检查,它已经涵盖了大部分检查,因为任何原始非对象都不是 HTMLElement 的实例,null 不是 HTMLElement 的实例,并且 HTMLElement 实例具有“nodeType”属性,但它继承自 proto 而不是自己的 属性, :
const isDOMElement = el => el instanceof HTMLElement
//or
const isDOMElement = el => el instanceof Node
大家可以试试...
function exposeImplementation(value) {
return Object
.prototype
.toString
.call(value);
}
function getInternalClassName(value) {
return (/^\[object\s+(?<className>[^\]]+)\]$/)
.exec(
exposeImplementation(value)
)
?.groups
?.className;
}
function isHTMLElement(value) {
return !!value && (/^HTML(?:[A-Z][A-Za-z]+)?Element$/)
.test(
String(
getInternalClassName(value)
)
);
}
console.log(
getInternalClassName(document.createElement('h1')),
isHTMLElement(document.createElement('h1'))
);
console.log(
getInternalClassName(document.body),
isHTMLElement(document.body)
);
console.log(
getInternalClassName(document),
isHTMLElement(document)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
现在我正在使用 isElement
by lodash 检查一个元素是否 DOM 可能。我想摆脱这个库,所以我正在寻找这个功能的纯 JS 实现。
我正在使用它,但我不知道它是否是正确的实现以及我是否忽略了任何边缘情况:
const isDOMElement = el => el instanceof HTMLElement
更新
我已经测试过(codepen link) the four proposed implementation, in all cases is working as expected, maybe the one proposed by @cesare covers most of the cases, but also the one proposed by @peter-seliger is clever and work with an "outside of the BOX" thinking. Finally, both @David Thomas 并且我第一次使用的那个适用于大多数情况。
总而言之,我认为,正如 David Thomas 指出的那样 It's just a matter of preference
。
P.S:测试用到的标签摘自MDN的HTML elements reference
P.S2:不确定如何进行以及接受什么答案。 cesare 和 peter 都有一个很好的观点
从库源代码看实现:
这是 lodash
实用程序:
function isElement(value) {
return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value)
}
基本上 isObjectLike
它检查传递的值是一个非 null
对象(因为 null 是 js 中的一个对象)并且 !isPlainObject
它不是一个普通对象(因为它可能是一个带有 "nodeType": 1 条目的对象,并且因为 HTMLElement 实例具有嵌套原型。
isPlainObject
实用程序是这样的:
function isPlainObject(value) {
if (!isObjectLike(value) || getTag(value) != '[object Object]') {
return false
}
if (Object.getPrototypeOf(value) === null) {
return true
}
let proto = value
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
如您所见,第一次检查是多余的,因为它再次检查 isObjectLike
,但我认为主要的警告是它不涵盖其他对象情况,因为例如“数组”是对象也因此他们通过了检查:
const arr = [1, 2]; // array
arr.nodeType = 1; // add nodeType property to the array object
console.log(isElement(arr)); // true Lodash
自己试一下。
我认为检查对象是否具有继承的 nodeType
属性 更安全:
const _isElement = (node) =>
typeof node === 'object' &&
node !== null &&
!node.hasOwnProperty('nodeType') &&
node.nodeType &&
node.nodeType === 1
const el = document.createElement('h1'); // node
const arr = [1, 2]; // array
arr.nodeType = 1; // add nodeType property to the array object
console.log(isElement(arr)); // true Lodash
console.log(isElement(el)); // true Lodash
console.log(_isElement(arr)) // false
console.log(_isElement(el)) // true
无论如何,我更喜欢使用你的检查,它已经涵盖了大部分检查,因为任何原始非对象都不是 HTMLElement 的实例,null 不是 HTMLElement 的实例,并且 HTMLElement 实例具有“nodeType”属性,但它继承自 proto 而不是自己的 属性, :
const isDOMElement = el => el instanceof HTMLElement
//or
const isDOMElement = el => el instanceof Node
大家可以试试...
function exposeImplementation(value) {
return Object
.prototype
.toString
.call(value);
}
function getInternalClassName(value) {
return (/^\[object\s+(?<className>[^\]]+)\]$/)
.exec(
exposeImplementation(value)
)
?.groups
?.className;
}
function isHTMLElement(value) {
return !!value && (/^HTML(?:[A-Z][A-Za-z]+)?Element$/)
.test(
String(
getInternalClassName(value)
)
);
}
console.log(
getInternalClassName(document.createElement('h1')),
isHTMLElement(document.createElement('h1'))
);
console.log(
getInternalClassName(document.body),
isHTMLElement(document.body)
);
console.log(
getInternalClassName(document),
isHTMLElement(document)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }