Trying to understand object and method creation in javascript - javascript

I'm trying to understand the different ways to create objects and methods in javascript. I've read a lot of articles, blogs and stackoverflow questions and I think I get the notion in general. But I've encountered a small javascript library (written in coffeescript) and the the way it creates objects and methods confused me a little.
I've included a snippet but if you want you can find the complete script at instafeed.js.
Code:
(function() {
var Instafeed, root;
Instafeed = (function() {
function Instafeed(params) {
var option, value;
this.options = {
target: 'instafeed',
get: 'popular',
resolution: 'thumbnail',
sortBy: 'most-recent',
links: true,
limit: 15,
mock: false
};
if (typeof params === 'object') {
for (option in params) {
value = params[option];
this.options[option] = value;
}
}
}
Instafeed.prototype.run = function() {
var header, instanceName, script;
if (typeof this.options.clientId !== 'string') {
if (typeof this.options.accessToken !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if (typeof this.options.accessToken !== 'string') {
if (typeof this.options.clientId !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if ((this.options.before != null) && typeof this.options.before === 'function') {
this.options.before.call(this);
}
if (typeof document !== "undefined" && document !== null) {
script = document.createElement('script');
script.id = 'instafeed-fetcher';
script.src = this._buildUrl();
header = document.getElementsByTagName('head');
header[0].appendChild(script);
instanceName = "instafeedCache" + this.unique;
window[instanceName] = new Instafeed(this.options);
window[instanceName].unique = this.unique;
}
return true;
}
...
return Instafeed;
})();
root = typeof exports !== "undefined" && exports !== null ? exports : window;
root.Instafeed = Instafeed;
}).call(this);
I'm having difficulties understanding the following:
Why did the author prefer to wrap everything with (function(){...}).call(this);? Maybe to avoid creating global variables?
What purpose does the .call(this) part at the very end of the script serve?
Why did the author create the root variable and what are the following lines for?
root = typeof exports !== "undefined" && exports !== null ? exports : window;
root.Instafeed = Instafeed;
Since this the preferred way to create objects and methods in coffeescript I suppose this is one of the better ways to do it. But its advantages over the following version escapes me:
function Instafeed(params) {
...
}
Instafeed.prototype.run = function() {
...
}

Yes; this makes all formerly top-level vars into local variables.
It makes this equal to the global object inside the function
It lets it work as a CommonJS module (for Node.js or Browserify)

Related

How to check for availability for a nested variable without checking all the preceding variable availability, in ReactNative?

For example, in iOS Swift, I can do something like this:
if (self.user?.company?.pic?.phoneNumber != null) { doSomething() }
Without the need to:
if (self.user != null && self.user!.company != null && self.user!.company!.pic != null && self.user!.company!.pic!.phoneNumber != null) { doSomething() }
In ReactNative (or Javascript), I found out that if an object is undefined, I can't check for the existence of the variable inside of it, so I have to check first whether the object is undefined or not, only then I can safely check whether the variable inside of it undefined or not.
if (typeof this.state.user !== "undefined" && typeof this.state.user.company !== "undefined" && typeof this.state.user.company.pic !== "undefined" && typeof this.state.user.company.pic.phoneNumber !== undefined) { this.doSomething() }
How can I turn this into just:
if (typeof this.state.user.company.pic.phoneNumber !== "undefined") { this.doSomething() }
or something similar?
Thanks.
Currently, optional chaining is a stage 3 draft, and so, you may be able to do it in the future.
EDIT:
Optional chaining will now be part of ES2020, and so you'll be able to do the following:
if (self.user?.company?.pic?.phoneNumber !== undefined) {
doSomething(); // phoneNumber exists
}
With that being said, it still has very limited browser support.
So, for the time being, you could instead create a function which recursively finds each object from a list of properties like so:
const optional_chain = (obj, [key, ...props]) =>
obj !== undefined && key ? optional_chain(obj[key], props) : obj;
const user = {
company: {
pic: {
phoneNumber: 1
}
}
}
console.log(optional_chain(user, ['company', 'pic', 'phoneNumber'])); // 1
console.log(optional_chain(user, ['company', 'pic', 'phoneNumber', 'x'])); // undefined
console.log(optional_chain(user, ['company', 'picture', 'phoneNumber'])); // undefined
console.log(optional_chain(user, ['x', 'picture', 'phoneNumber'])); // undefined
In your case, the usage would be as so:
if (optional_chain(self.user, ['company', 'pic', 'phoneNumber']) !== undefined) {
doSomething();
}
If you can’t use optional chaining which is still a proposal but available via babel plugin you could use a recursive utility function to test for the presence of each path segment:
const pluck = (item, path) => {
const [, part, rest] = /^([^.]+)\.*(.*)/.exec(path) || [];
if (!part) {
return null;
}
const o = (item || {})[part];
if (o == null) {
return null;
}
return rest.length ? pluck(o, rest) : o;
};
if (pluck(this.state, ‘user.company.pic.phoneNumber’)) {
doSomething();
}

Each loop to check if function exists

I am developing a site using a third-party CMS and I have to include functions across various parts of the content depending on which page is being displayed. To reduce the amount of functions being called on each page load, I would like to loop through an array of functions to check if they exist before firing them.
This single function would then be called at body onload.
I have adapted code from Javascript Array of Functions and How to implement an array of functions in Javascript? as well as isFunction.
My understanding was that I could put the functions in an array without () and they would not be called but in my console in Chrome an Uncaught Reference error is generated on the line in the array where a function name is mentioned.
e.g. the jb_underimage_height function is not in the code on all pages, so this generates the error when it does not exist.
Here is the code so far:
function jb_onloads() {
var functionArray = [
jb_category_price_POA,
jb_highlight_tech_columns,
jb_underimage_height,
jb_moveGuestButton,
jb_loginCheck,
jb_moveRefineSpan,
jb_style_from_url,
materials_dropdown,
jb_remove_search_spaces,
jb_init_social,
checkCookies,
jb_category_change_class,
jb_move_basket_text,
jb_style_form,
jb_checkNotifyEnvelope
]; // end of functionArray
$.each(functionArray, function(key, value) {
if(typeof functionArray[key] !== 'undefined' && typeof functionArray[key] === "function") { functionArray[key](); }
});
} // end of jb_onloads
And this was my workaround when I had to this.
function a() { alert ("I am a") };
function b() { alert ("I am b") };
var arr = [
typeof a === "function" && a || 0,
typeof b === "function" && b || 0,
typeof c === "function" && c || 0
];
arr.forEach(function(func) {
if(typeof func === "function") {
func();
}
});
maybe we can do it as:
1 function defining:
if (typeof myFuncCollections == "undefined") // window.myFuncCollections
myFuncCollections = {};
myFuncCollections.func1 = function func1() {
console.log("func1");
};
//or
myFuncCollections['funcname'] = function funcname() {
console.log("funcname");
}
....
2 jb_onloads()
function jb_onloads() {
if (typeof myFuncCollections == "undefined")
myFuncCollections = {};
$.each(myFuncCollections, function(i) {
myFuncCollections[i]();
});
}
3 call jb_onloads() after including 1 and 2. And That do not require inlcuding 1-script before 2-script. Also, your can use any function in 1-script outside jb_onloads after including 1-script.
Since using Global value, please use special prefix for naming your "myFuncCollections"
You are trying to insert function references to the array. But if the function is not defined then that name does not exists and thus the error.
Add them as strings
function jb_onloads() {
var functionArray = [
'jb_category_price_POA',
'jb_highlight_tech_columns',
'jb_underimage_height',
'jb_moveGuestButton',
'jb_loginCheck',
'jb_moveRefineSpan',
'jb_style_from_url',
'materials_dropdown',
'jb_remove_search_spaces',
'jb_init_social',
'checkCookies',
'jb_category_change_class',
'jb_move_basket_text',
'jb_style_form',
'jb_checkNotifyEnvelope'
]; // end of functionArray
$.each(functionArray, function(index, functionName) {
// assuming functions are in the global scope
var func = window[ functionName ],
funcType = typeof func;
if (funcType === "function") {
func();
}
});
} // end of jb_onloads

Create a global function in JavaScript

I'm trying to create a global function where I can use it anywhere inside a .js file.
We have more than 50 javascript files joined together and inside each files I want to be able to use this library anywhere.
Localized.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(factory);
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like enviroments that support module.exports,
// like Node.
module.exports = factory();
} else {
// Browser globals (root is window)
if (typeof Localized !== 'undefined') {
throw 'Localized" already in use';
}
root.Localized = factory();
}
}(this, function () {
var _strings,
_readyCallback,
_isReady = false,
_requestedStrings = false;
function ready( data ) {
_readyCallback = _readyCallback || function(){};
function domReady() {
// If the DOM isn't ready yet, repeat when it is
if ( document.readyState !== "complete" ) {
document.onreadystatechange = domReady;
return;
}
document.onreadystatechange = null;
_strings = data;
_isReady = true;
_readyCallback();
}
domReady();
}
// Get the current lang from the document's HTML element, which the
// server set when the page was first rendered. This saves us having
// to pass extra locale info around on the URL.
function getCurrentLang() {
var html = document.querySelector( "html" );
return html && html.lang ? html.lang : "en-US";
}
var Localized = {
get: function( key ) {
if ( !_strings ) {
console.error( "[goggles.webmaker.org] Error: string catalog not found." );
return "";
}
return ( _strings[ key ] || "" );
},
getCurrentLang: getCurrentLang,
// Localized strings are ready
ready: function( cb ) {
if ( !_requestedStrings ) {
_requestedStrings = true;
_readyCallback = cb;
function onload( data ) {
ready( data );
}
onload.error = console.log;
var xhr = new XMLHttpRequest();
xhr.open('GET', '/strings/' + getCurrentLang() + '?bust=' + Date.now(), false);
xhr.send(null);
if (xhr.status !== 200) {
err = new Error(id + ' HTTP status: ' + status);
err.xhr = xhr;
onload.error(err);
return;
}
onload(JSON.parse(xhr.responseText));
};
if ( _isReady ) {
_readyCallback();
}
},
isReady: function() {
return !!_isReady;
}
};
return Localized;
}));
So I want to be able to go into any of the 50 files and do Localized.get("something");
But then I don't even have the Localized object available in the web console. For example if you have jQuery you can do $ in the web console and you can do anything there.
Have you ever looked at the Three.js global function? It's super easy to understand!
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.THREE = global.THREE || {})));
}(this, (function (exports) { 'use strict';
So it turns out that my javascript is globally defined and accessible everywhere within the file that is included and it can be call from the console as well except I have to initialize that by doing Localized.ready(function(){}); then I can get it to work.
So if anyone is looking to create their own global function and make it standard they can follow this way.
amdWeb.js is what I use as a standard to create global function.

What are the best practices to make a plugin CJS, AMD, and script-tag friendly to also be CJS/AMD/script-tag ready?

I'm attempting to write a plugin for a library (MomentJS) that is usable almost everywhere. I'm planning on using it with RequireJS, so it has to be AMD friendly, but I'd also like to go ahead and make it usable by those who load it via script tags in the browser or in Node.
After poking around, I slapped this together:
(function() {
var hasModule = typeof module !== "undefined" && module.exports;
var MY_LIB_DEF = function (moment, global) {
if(typeof moment == "undefined") {
throw "Can't find moment";
}
var MY_LIB = {
//
//DEFINE PLUGIN
//
};
if(hasModule) {
module.exports = LIB
} else if(global) {
global.LIB = LIB;
} else {
return LIB;
}
};
if(hasModule) {
moment = require('moment');
}
if (typeof define === "function" && define.amd) {
define(["moment"], MY_LIB_DEF);
} else {
MY_LIB_DEF(moment, this);
}
})();
The bottom section of MY_LIB_DEF where I determine if I'm exporting for CJS, attatching to window, or returning for AMD seems a bit clunky as does my picking of which way to kick off (CJS and script loading would share the running of the defining function. But the "global" passed into it will never be used).
While the above works, I'm thinking that this problem has to have been solved already. I just can't seem to find any examples to follow.
Anyone aware of better practices for this?
After searching around, I found some good info here to help solve the problem. Still had to massage it a bit for my purpose, but it seems to be the solution.
(function(root, definition) {
"use strict";
var moment;
if (typeof module !== 'undefined' && module.exports) {
moment = require('moment');
module.exports = definition(moment);
} else if (typeof define === 'function' && define.amd){
define(['moment'], definition);
} else {
root['MY_LIB'] = definition(root.moment);
}
}(this, function(moment) {
if(typeof moment === "undefined") {
throw "Can't find moment";
}
return {
foo: function() {
console.log('bar');
}
};
}));

Safest way to detect native DOM element? [duplicate]

I'm trying to get:
document.createElement('div') //=> true
{tagName: 'foobar something'} //=> false
In my own scripts, I used to just use this since I never needed tagName as a property:
if (!object.tagName) throw ...;
So for the second object, I came up with the following as a quick solution -- which mostly works. ;)
The problem is, it depends on browsers enforcing read-only properties, which not all do.
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;
}
}
Is there a good substitute?
This might be of interest:
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");
}
}
It's part of the DOM, Level2.
Update 2: This is how I implemented it in my own library:
(the previous code didn't work in Chrome, because Node and HTMLElement are functions instead of the expected object. This code is tested in FF3, IE7, Chrome 1 and 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"
);
}
The accepted answer is a bit complicated, and does not detect all types of HTML elements. For example, SVG elements are not supported. In contrast, this answer works for HTML as well as SVG, etc.
See it in action here: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
Cherry on top: the above code is IE8 compatible.
No need for hacks, you can just ask if an element is an instance of the DOM Element:
const isDOM = el => el instanceof Element
All solutions above and below (my solution including) suffer from possibility of being incorrect, especially on IE — it is quite possible to (re)define some objects/methods/properties to mimic a DOM node rendering the test invalid.
So usually I use the duck-typing-style testing: I test specifically for things I use. For example, if I want to clone a node I test it like this:
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);
}
Basically it is a little sanity check + the direct test for a method (or a property) I am planning to use.
Incidentally the test above is a good test for DOM nodes on all browsers. But if you want to be on the safe side always check the presence of methods and properties and verify their types.
EDIT: IE uses ActiveX objects to represent nodes, so their properties do not behave as true JavaScript object, for example:
console.log(typeof node.cloneNode); // object
console.log(node.cloneNode instanceof Function); // false
while it should return "function" and true respectively. The only way to test methods is to see if the are defined.
A simple way to test if a variable is a DOM element (verbose, but more traditional syntax :-)
function isDomEntity(entity) {
if(typeof entity === 'object' && entity.nodeType !== undefined){
return true;
}
else{
return false;
}
}
Or as HTMLGuy suggested (short and clean syntax):
const isDomEntity = entity =>
typeof entity === 'object' && entity.nodeType !== undefined
You could try appending it to a real DOM node...
function isDom(obj)
{
var elm = document.createElement('div');
try
{
elm.appendChild(obj);
}
catch (e)
{
return false;
}
return true;
}
How about Lo-Dash's _.isElement?
$ npm install lodash.iselement
And in the code:
var isElement = require("lodash.iselement");
isElement(document.body);
This is from the lovely JavaScript library MooTools:
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
}
The using the root detection found here, we can determine whether e.g. alert is a member of the object's root, which is then likely to be a window:
function isInAnyDOM(o) {
return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}
To determine whether the object is the current window is even simpler:
function isInCurrentDOM(o) {
return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}
This seems to be less expensive than the try/catch solution in the opening thread.
Don P
old thread, but here's an updated possibility for ie8 and ff3.5 users:
function isHTMLElement(o) {
return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}
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; },
// In fact I am more likely t use these inline, but sometimes it is good to have these shortcuts for setup code
I think prototyping is not a very good solution but maybe this is the fastest one:
Define this code block;
Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;
than check your objects isDomElement property:
if(a.isDomElement){}
I hope this helps.
This could be helpful: 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);
}
In the code above, we use the double negation operator to get the boolean value of the object passed as argument, this way we ensure that each expression evaluated in the conditional statement be boolean, taking advantage of the Short-Circuit Evaluation, thus the function returns true or false
According to mdn
Element is the most general base class from which all objects in a Document inherit. It only has methods and properties common to all kinds of elements.
We can implement isElement by prototype. Here is my advice:
/**
* #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
I think that what you have to do is make a thorough check of some properties that will always be in a dom element, but their combination won't most likely be in another object, like so:
var isDom = function (inp) {
return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};
In Firefox, you can use the instanceof Node. That Node is defined in DOM1.
But that is not that easy in IE.
"instanceof ActiveXObject" only can tell that it is a native object.
"typeof document.body.appendChild=='object'" tell that it may be DOM object, but also can be something else have same function.
You can only ensure it is DOM element by using DOM function and catch if any exception. However, it may have side effect (e.g. change object internal state/performance/memory leak)
Perhaps this is an alternative? Tested in Opera 11, FireFox 6, Internet Explorer 8, Safari 5 and 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;
}
Function won't be fooled by e.g. this
isDOMNode( {'nodeName':'fake'} ); // returns false
You can see if the object or node in question returns a string type.
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
This is what I figured out:
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";
}
}
})();
To improve performance I created a self-invoking function that tests the browser's capabilities only once and assigns the appropriate function accordingly.
The first test should work in most modern browsers and was already discussed here. It just tests if the element is an instance of HTMLElement. Very straightforward.
The second one is the most interesting one. This is its core-functionality:
return el instanceof (document.createElement(el.nodeName)).constructor
It tests whether el is an instance of the construcor it pretends to be. To do that, we need access to an element's contructor. That's why we're testing this in the if-Statement. IE7 for example fails this, because (document.createElement("a")).constructor is undefined in IE7.
The problem with this approach is that document.createElement is really not the fastest function and could easily slow down your application if you're testing a lot of elements with it. To solve this, I decided to cache the constructors. The object ElementConstructors has nodeNames as keys with its corresponding constructors as values. If a constructor is already cached, it uses it from the cache, otherwise it creates the Element, caches its constructor for future access and then tests against it.
The third test is the unpleasant fallback. It tests whether el is an object, has a nodeType property set to 1 and a string as nodeName. This is not very reliable of course, yet the vast majority of users shouldn't even fall back so far.
This is the most reliable approach I came up with while still keeping performance as high as possible.
Test if obj inherits from Node.
if (obj instanceof Node){
// obj is a DOM Object
}
Node is a basic Interface from which HTMLElement and Text inherit.
For the ones using Angular:
angular.isElement
https://docs.angularjs.org/api/ng/function/angular.isElement
This will work for almost any browser. (No distinction between elements and nodes here)
function dom_element_check(element){
if (typeof element.nodeType !== 'undefined'){
return true;
}
return false;
}
differentiate a raw js object from a HTMLElement
function isDOM (x){
return /HTML/.test( {}.toString.call(x) );
}
use:
isDOM( {a:1} ) // false
isDOM( document.body ) // true
// OR
Object.defineProperty(Object.prototype, "is",
{
value: function (x) {
return {}.toString.call(this).indexOf(x) >= 0;
}
});
use:
o={}; o.is("HTML") // false
o=document.body; o.is("HTML") // true
here's a trick using jQuery
var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")
$(obj).html() == undefined // true
$(element).html() == undefined // false
so putting it in a function:
function isElement(obj){
return (typeOf obj === 'object' && !($(obj).html() == undefined));
}
Not to hammer on this or anything but for ES5-compliant browsers why not just:
function isDOM(e) {
return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}
Won't work on TextNodes and not sure about Shadow DOM or DocumentFragments etc. but will work on almost all HTML tag elements.
A absolute right method, check target is a real html element
primary code:
(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);
Each DOMElement.constructor returns function HTML...Element() or [Object HTML...Element] so...
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;
}
I have a special way to do this that has not yet been mentioned in the answers.
My solution is based on four tests. If the object passes all four, then it is an element:
The object is not null.
The object has a method called "appendChild".
The method "appendChild" was inherited from the Node class, and isn't just an imposter method (a user-created property with an identical name).
The object is of Node Type 1 (Element). Objects that inherit methods from the Node class are always Nodes, but not necessarily Elements.
Q: How do I check if a given property is inherited and isn't just an imposter?
A: A simple test to see if a method was truly inherited from Node is to first verify that the property has a type of "object" or "function". Next, convert the property to a string and check if the result contains the text "[Native Code]". If the result looks something like this:
function appendChild(){
[Native Code]
}
Then the method has been inherited from the Node object. See https://davidwalsh.name/detect-native-function
And finally, bringing all the tests together, the solution is:
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;
}
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element
This will check for even if it is a jQuery or JavaScript DOM element
The only way to guarentee you're checking an actual HTMLEement, and not just an object with the same properties as an HTML Element, is to determine if it inherits from Node, since its impossible to make a new Node() in JavaScript. (unless the native Node function is overwritten, but then you're out of luck). So:
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--!>

Categories