- How to Check if a Class Exists with JavaScript
- classList.contains() formula
- The Uncluttered News Feed
- HTML for our news feed
- CSS Styling
- The JavaScript
- How the JavaScript code works
- Resources
- Has this been helpful to you?
- Class checking: «instanceof»
- The instanceof operator
- Bonus: Object.prototype.toString for the type
- Symbol.toStringTag
- Summary
- Tasks
- Strange instanceof
- Comments
How to Check if a Class Exists with JavaScript
Checking if a class exists on an element is simple and fast with the JavaScript classList property’s contains() method.
Let’s first take a look at the generic formula for using classList.contains() and then we’ll look at a practical use case.
classList.contains() formula
var element = document.querySelector("selector") element.classList.contains("class")
In the generic example above we use the versatile querySelector() method to find our target element via its selector name. The selector could be a class selector, element selector, or another selector type.
We then assign the element we found with querySelector() to our declared element variable.
Then we attach the classList property’s contains() method to our element via its variable reference. Then inside the contains() method’s argument (inside the parenthesis) we specify the name of the ‘class’ we want to check if exists.
Generic examples are boring, let’s get practical!
The Uncluttered News Feed
Filtering with classList.contains()
— a practical use case
You’re visiting a website with a mixed news feed of many different categories. But you’re only interested in reading about technology.
Cluttered news feeds are blasphemous. Let’s filter out all the other categories, using the classList.contains() method.
First, let’s add some HTML so we have some content to work with. Then we’ll style it quickly, and move on to the JavaScript.
HTML for our news feed
div class="wrapper"> h1>Newsfeedh1> div class="news-feed"> h3 class="headline"> a class="link category-health" href="#">Healtha> h3> h3 class="headline"> a class="link category-finances" href="#">Financesa> h3> h3 class="headline"> a class="link category-politics" href="#">Politicsa> h3> h3 class="headline"> a class="link category-nature" href="#">Naturea> h3> h3 class="headline"> a class="link category-humor" href="#">Humora> h3> h3 class="headline"> a class="link category-weather" href="#">Weathera> h3> h3 class="headline"> a class="link category-technology" href="#">Technologya> h3> h3 class="headline"> a class="link category-sports" href="#">Sportsa> h3> div> div class="fixed-container"> span>Filter:span> button class="btn-technology">Technologybutton> div> div>
For our HTML content we have:
- A big headline.
- A news feed with different categories.
- Outside of the news feed, we have a button called Technology. This is the button we’ll use to toggle (hide/show) all non-technology topics.
Obviously, our news feed example above only has a few news items (for illustration purposes), so it doesn’t look cluttered. But a real mixed news feed there would be a myriad of articles from each news category, flooding the feed. That’s when filtering buttons are useful.
CSS Styling
All the following CSS is cosmetic and optional, except the .js-hide class, which is a helper class we’ll use with JavaScript in the next segment.
body font-family: "Source Sans Pro", "Helvetica", "Sans-Serif"; > .wrapper position: relative; padding-left: 1rem; padding-right: 1rem; margin: 2rem auto; max-width: 50em; > .news-feed border: 1px solid #eee; max-height: 256px; overflow-y: scroll; > .headline font-size: 1.25rem; padding: 0.25rem 1.5rem; > .link color: #252525; text-decoration: none; > .fixed-container position: fixed; bottom: 0; left: 0; padding: 1.5rem; > .btn-technology cursor: pointer; font-size: 1rem; padding: 0.5rem 1rem; margin-top: 2rem; margin-left: 1rem; border-radius: 4px; border: 1px solid #82b97e; outline: none; > .js-hide display: none; >
Just make sure you add that .js-hide class to your CSS stylesheet and let’s move on to JavaScript!
The JavaScript
Copy and paste the following code into your JS file. I’ll explain how everything works right below.
var btnTechnology = document.querySelector(".btn-technology") var allNewsCategories = document.querySelectorAll(".news-feed .link") function showCategoryTechnology() for (var i = 0; i allNewsCategories.length; i++) if (!allNewsCategories[i].classList.contains("category-technology")) allNewsCategories[i].parentElement.classList.toggle("js-hide") > > > btnTechnology.addEventListener("click", showCategoryTechnology)
How the JavaScript code works
- First we use querySelector() to grab our Technlogy button element via its class selector .btn-technology . which will act as the trigger for our filtering function later. We assign our button element to a variable called btn-technology .
- Then we use querySelectorAll() to grab all our News Feed ( .news-feed ) items and select each item link by their class name ( .link ). We then assign all our news item links to a variable called allNewsCategories .
- Then we create a function, showCategoryTechnology() <..>which we’ll call when the Technology button is clicked.
- Inside the function body, we loop through all items () inside the News Feed element and store them in an array [i]
- Inside the loop, we add a conditional if statement which says: “if any of the items on the list we just iterated through do not contain the class .category-technology — then run the classList.toggle method with the .js-hide class on those items.
- On the last line, we attach the addEventListener() method to our button element. We tell the event listener to listen for a ‘click’ event. When the button is clicked, it calls the showCategoryTechnology() function, which runs the entire code block that makes this toggling feature possible.
The ! symbol (Logical Operator) that we put in front of allNewsCategories[i] is what handles the “not” part of our if statement. If you remove ! then our code will do the opposite of what it does now.
We could also have used classList.remove() to remove our unwanted news items. But in most cases, it makes sense to give our users the option of hiding/showing items, which is what classList.toggle() does.
Resources
Has this been helpful to you?
You can support my work by sharing this article with others, or perhaps buy me a cup of coffee 😊
Class checking: «instanceof»
The instanceof operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
Such a check may be necessary in many cases. For example, it can be used for building a polymorphic function, the one that treats arguments differently depending on their type.
The instanceof operator
It returns true if obj belongs to the Class or a class inheriting from it.
class Rabbit <> let rabbit = new Rabbit(); // is it an object of Rabbit class? alert( rabbit instanceof Rabbit ); // true
It also works with constructor functions:
// instead of class function Rabbit() <> alert( new Rabbit() instanceof Rabbit ); // true
…And with built-in classes like Array :
let arr = [1, 2, 3]; alert( arr instanceof Array ); // true alert( arr instanceof Object ); // true
Please note that arr also belongs to the Object class. That’s because Array prototypically inherits from Object .
Normally, instanceof examines the prototype chain for the check. We can also set a custom logic in the static method Symbol.hasInstance .
The algorithm of obj instanceof Class works roughly as follows:
- If there’s a static method Symbol.hasInstance , then just call it: Class[Symbol.hasInstance](obj) . It should return either true or false , and we’re done. That’s how we can customize the behavior of instanceof . For example:
// setup instanceOf check that assumes that // anything with canEat property is an animal class Animal < static [Symbol.hasInstance](obj) < if (obj.canEat) return true; >> let obj = < canEat: true >; alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? . // if any answer is true, return true // otherwise, if we reached the end of the chain, return false
In the example above rabbit.__proto__ === Rabbit.prototype , so that gives the answer immediately. In the case of an inheritance, the match will be at the second step:
class Animal <> class Rabbit extends Animal <> let rabbit = new Rabbit(); alert(rabbit instanceof Animal); // true // rabbit.__proto__ === Animal.prototype (no match) // rabbit.__proto__.__proto__ === Animal.prototype (match!)
Here’s the illustration of what rabbit instanceof Animal compares with Animal.prototype :
By the way, there’s also a method objA.isPrototypeOf(objB), that returns true if objA is somewhere in the chain of prototypes for objB . So the test of obj instanceof Class can be rephrased as Class.prototype.isPrototypeOf(obj) .
It’s funny, but the Class constructor itself does not participate in the check! Only the chain of prototypes and Class.prototype matters.
That can lead to interesting consequences when a prototype property is changed after the object is created.
function Rabbit() <> let rabbit = new Rabbit(); // changed the prototype Rabbit.prototype = <>; // . not a rabbit any more! alert( rabbit instanceof Rabbit ); // false
Bonus: Object.prototype.toString for the type
We already know that plain objects are converted to string as [object Object] :
let obj = <>; alert(obj); // [object Object] alert(obj.toString()); // the same
That’s their implementation of toString . But there’s a hidden feature that makes toString actually much more powerful than that. We can use it as an extended typeof and an alternative for instanceof .
Sounds strange? Indeed. Let’s demystify.
By specification, the built-in toString can be extracted from the object and executed in the context of any other value. And its result depends on that value.
- For a number, it will be [object Number]
- For a boolean, it will be [object Boolean]
- For null : [object Null]
- For undefined : [object Undefined]
- For arrays: [object Array]
- …etc (customizable).
// copy toString method into a variable for convenience let objectToString = Object.prototype.toString; // what type is this? let arr = []; alert( objectToString.call(arr) ); // [object Array]
Here we used call as described in the chapter Decorators and forwarding, call/apply to execute the function objectToString in the context this=arr .
Internally, the toString algorithm examines this and returns the corresponding result. More examples:
let s = Object.prototype.toString; alert( s.call(123) ); // [object Number] alert( s.call(null) ); // [object Null] alert( s.call(alert) ); // [object Function]
Symbol.toStringTag
The behavior of Object toString can be customized using a special object property Symbol.toStringTag .
let user = < [Symbol.toStringTag]: "User" >; alert( <>.toString.call(user) ); // [object User]
For most environment-specific objects, there is such a property. Here are some browser specific examples:
// toStringTag for the environment-specific object and class: alert( window[Symbol.toStringTag]); // Window alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest alert( <>.toString.call(window) ); // [object Window] alert( <>.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
As you can see, the result is exactly Symbol.toStringTag (if exists), wrapped into [object . ] .
At the end we have “typeof on steroids” that not only works for primitive data types, but also for built-in objects and even can be customized.
We can use <>.toString.call instead of instanceof for built-in objects when we want to get the type as a string rather than just to check.
Summary
Let’s summarize the type-checking methods that we know:
works for | returns | |
---|---|---|
typeof | primitives | string |
<>.toString | primitives, built-in objects, objects with Symbol.toStringTag | string |
instanceof | objects | true/false |
As we can see, <>.toString is technically a “more advanced” typeof .
And instanceof operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
Tasks
Strange instanceof
In the code below, why does instanceof return true ? We can easily see that a is not created by B() .
function A() <> function B() <> A.prototype = B.prototype = <>; let a = new A(); alert( a instanceof B ); // true
Yeah, looks strange indeed.
But instanceof does not care about the function, but rather about its prototype , that it matches against the prototype chain.
And here a.__proto__ == B.prototype , so instanceof returns true .
So, by the logic of instanceof , the prototype actually defines the type, not the constructor function.
Comments
- If you have suggestions what to improve — please submit a GitHub issue or a pull request instead of commenting.
- If you can’t understand something in the article – please elaborate.
- To insert few words of code, use the tag, for several lines – wrap them in tag, for more than 10 lines – use a sandbox (plnkr, jsbin, codepen…)