Alternative to array.some() method? - javascript

Is there an alternative to using array.some()?
I've had it in my code for a while but I just learned that its not supported by IE8.
My original code:
var list = ['Johny', 'Adam', 'Johny'];
var option = 'Johny';
var foundInList = list.some(function (el) {
return el === option;
});
I could replace it with something like :
var test = false;
for (i = 0; i < list.length; i++){
if (list[i] === option){
test = true;
break;
}
}
But there may be a better way to do the same.
Please help.
Thanks in Advance
PS: Here's a fiddle

I think your best solution here is just a bespoke for loop over the entries. Most array mutation methods are not supported in IE8. I would recommend not polyfilling to replace the function because your polyfill may not efficiently replace the function in modern browsers.

You can add your own some method
if (!Array.prototype.some)
{
Array.prototype.some = function (func)
{
for (var i in this)
{
if (func(i)) return true;
}
return false;
};
}

Related

Check if visible div's <a> hasClass '.white' - Jquery to Javascript [duplicate]

How do you do jQuery’s hasClass with plain ol’ JavaScript? For example,
<body class="foo thatClass bar">
What’s the JavaScript way to ask if <body> has thatClass?
Simply use classList.contains():
if (document.body.classList.contains('thatClass')) {
// do some stuff
}
Other uses of classList:
document.body.classList.add('thisClass');
// $('body').addClass('thisClass');
document.body.classList.remove('thatClass');
// $('body').removeClass('thatClass');
document.body.classList.toggle('anotherClass');
// $('body').toggleClass('anotherClass');
Browser Support:
Chrome 8.0
Firefox 3.6
IE 10
Opera 11.50
Safari 5.1
classList Browser Support
You can check whether element.className matches /\bthatClass\b/.
\b matches a word break.
Or, you can use jQuery's own implementation:
var className = " " + selector + " ";
if ( (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(" thatClass ") > -1 )
To answer your more general question, you can look at jQuery's source code on github or at the source for hasClass specifically in this source viewer.
The most effective one liner that
returns a boolean (as opposed to Orbling's answer)
Does not return a false positive when searching for thisClass on an element that has class="thisClass-suffix".
is compatible with every browser down to at least IE6
function hasClass( target, className ) {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(target.className);
}
// 1. Use if for see that classes:
if (document.querySelector(".section-name").classList.contains("section-filter")) {
alert("Grid section");
// code...
}
<!--2. Add a class in the .html:-->
<div class="section-name section-filter">...</div>
The attribute that stores the classes in use is className.
So you can say:
if (document.body.className.match(/\bmyclass\b/)) {
....
}
If you want a location that shows you how jQuery does everything, I would suggest:
http://code.jquery.com/jquery-1.5.js
Element.matches()
Instead of $(element).hasClass('example') in jQuery, you can use element.matches('.example') in plain JavaScript:
if (element.matches('.example')) {
// Element has example class ...
}
View Browser Compatibility
hasClass function:
HTMLElement.prototype.hasClass = function(cls) {
var i;
var classes = this.className.split(" ");
for(i = 0; i < classes.length; i++) {
if(classes[i] == cls) {
return true;
}
}
return false;
};
addClass function:
HTMLElement.prototype.addClass = function(add) {
if (!this.hasClass(add)){
this.className = (this.className + " " + add).trim();
}
};
removeClass function:
HTMLElement.prototype.removeClass = function(remove) {
var newClassName = "";
var i;
var classes = this.className.replace(/\s{2,}/g, ' ').split(" ");
for(i = 0; i < classes.length; i++) {
if(classes[i] !== remove) {
newClassName += classes[i] + " ";
}
}
this.className = newClassName.trim();
};
I use a simple/minimal solution, one line, cross browser, and works with legacy browsers as well:
/\bmyClass/.test(document.body.className) // notice the \b command for whole word 'myClass'
This method is great because does not require polyfills and if you use them for classList it's much better in terms of performance. At least for me.
Update: I made a tiny polyfill that's an all round solution I use now:
function hasClass(element,testClass){
if ('classList' in element) { return element.classList.contains(testClass);
} else { return new Regexp(testClass).exec(element.className); } // this is better
//} else { return el.className.indexOf(testClass) != -1; } // this is faster but requires indexOf() polyfill
return false;
}
For the other class manipulation, see the complete file here.
a good solution for this is to work with classList and contains.
i did it like this:
... for ( var i = 0; i < container.length; i++ ) {
if ( container[i].classList.contains('half_width') ) { ...
So you need your element and check the list of the classes. If one of the classes is the same as the one you search for it will return true if not it will return false!
This 'hasClass' function works in IE8+, FireFox and Chrome:
hasClass = function(el, cls) {
var regexp = new RegExp('(\\s|^)' + cls + '(\\s|$)'),
target = (typeof el.className === 'undefined') ? window.event.srcElement : el;
return target.className.match(regexp);
}
[Updated Jan'2021] A better way:
hasClass = (el, cls) => {
[...el.classList].includes(cls); //cls without dot
};
Use something like:
Array.prototype.indexOf.call(myHTMLSelector.classList, 'the-class');
if (document.body.className.split(/\s+/).indexOf("thatClass") !== -1) {
// has "thatClass"
}
Well all of the above answers are pretty good but here is a small simple function I whipped up. It works pretty well.
function hasClass(el, cn){
var classes = el.classList;
for(var j = 0; j < classes.length; j++){
if(classes[j] == cn){
return true;
}
}
}
What do you think about this approach?
<body class="thatClass anotherClass"> </body>
var bodyClasses = document.querySelector('body').className;
var myClass = new RegExp("thatClass");
var trueOrFalse = myClass.test( bodyClasses );
https://jsfiddle.net/5sv30bhe/

Function to check if element has any of these classes with native JS

<div id="test" class="a1 a2 a5"></div>
var element = document.getElementById("test")
if (hasAnyOfTheseClasses(element, ["a1", "a6"])) {
//...
}
Looking for a simple, lightweight function to check if a function has any of the listed classes without jQuery or another library.
Such function would be easy to implement, but there should be a canonical, fastest and simplest answer people can just copy-paste.
This seems vampire-ish, but I'm asking this so googlers won't have to write it themselves.
Not a duplicate - the linked question checks for one class, this question asks for checking any of the classes.
A jQuery version exists here.
Here's a functional implementation using Array.some and Element.classList.contains.
function hasAnyClass(element, classes) {
return classes.some(function(c) {
return element.classList.contains(c);
});
}
var div = document.getElementById("test");
console.log(hasAnyClass(div, ["hi", "xyz"]));
console.log(hasAnyClass(div, ["xyz", "there"]));
console.log(hasAnyClass(div, ["xyz", "xyz"]));
<div id="test" class="hi there"></div>
Note that these functions are not supported on older versions of IE, and will require a shim/polyfill.
You could use a regex, not sure that it's purely better but at least more flexible since your current test relies too much on spaces being entered correctly.
function hasAnyOfTheseClasses(element, classes) {
var className = element.className;
for (var i = 0; i < classes.length; i++) {
var exp = new RegExp('\b'+classes[i] + '\b');
if(exp.test(className)) return true;
}
return false;
}
just create a loop that check if each value in your array is a class in your passed element
function hasAnyOfTheseClasses(elem, tofind) {
classes = elem.className.split(' ');
for(var x in tofind) {
var className = tofind[x];
if (classes.indexOf(className) == -1){
return false;
}
}
return true;
}
Here's my implementation:
function hasAnyOfTheseClasses(element, classes) {
for (var i = 0; i < classes.length; i++) {
if ((' ' + element.className + ' ').indexOf(' ' + classes[i] + ' ') > -1) {
return true;
}
}
return false;
}
It's not elegant or fast. Works though. Feel free to edit to improve.
Use the .classList property to get the list of classes of an element. Then you can use the .contains() method to test each of the classes.
function hasAnyOfTheseClass(element, classes) {
var classList = element.classList;
return classes.some(function(class) {
return classList.contains(class);
});
}
How about using Array.prototype.some() and Array.prototype.indexOf():
function hasAnyClass(el, classes) {
var elClasses = el.className.split(' ');
return classes.some(c => elClasses.indexOf(c) >= 0)
}

DRY up htmlCollection to Array calls

I have a function that is currently using the .getElementBy... DOM calls in JavaScript.
var $ = function (selector) {
var elements = [];
var lastSelector = selector.substring(selector.search(/[^#.]+$/), selector.length);
if(selector.includes('#') !== true || selector.includes('.') !== true) {
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
}
return elements;
};
There are a number of other if statements in the function using the code:
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
or
elements.push(document.getElementsByClassName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
Ideally i'd like to DRY up the repeated:
elements = Array.prototype.slice.call(elements[0]);
but I cannot define it before the if statements because elements has not yet been populated. It therefore tries to run the code on an empty array and errors.
Any suggestions?
Instead of using a home-brew limited function for selecting elements by a selector, you could just use the standard querySelectorAll() available in all browsers including IE8+.
As for converting an array-like object (e. g. a DOM collection) to a real Array (what Array.prototype.slice.call() is used for in your code), I use the following function:
var arrayFrom = function(arrayLike) {
if (Array.from) {
return Array.from(arrayLike);
}
var items;
try {
items = Array.prototype.slice.call(arrayLike, 0);
}
catch(e) {
items = [];
var count = arrayLike.length;
for (var i = 0; i < count; i++) {
items.push(arrayLike[i]);
}
}
return items;
};
or its following simplified version if browsers not supporting passing a non-Array argument to Array.prototype.slice.call() (IE8- if I recall correctly) don’t matter:
var arrayFrom = function(arrayLike) {
return Array.from
? Array.from(arrayLike);
: Array.prototype.slice.call(arrayLike, 0);
};
Certainly consider #marat-tanalin answer. In the case where using querySelectorAll() is not an option, the following worked for me, thanks #master565 for the help:
To start, wrapping the lines:
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
in a function:
function pushByTag(selector) {
elements.push(document.getElementsByTagName(selector));
elements = Array.prototype.slice.call(elements[0]);
}
Dried things up considerably. Then setting a variable for the if argument helped a lot:
if(selector.includes('#') !== true || selector.includes('.') !== true)
became:
var noClassOrId = selector.includes('#') !== true || selector.includes('.') !== true;
Both these refactors allowed me to single line my if statement in to something I'd argue was fairly readable:
if (noClassOrId) pushByTag(lastSelector);

How do I parse the results of a querySelectorAll selector engine & allow method chaining?

SIMPLIFIED EXAMPLE CODE:
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(), node = node || document.body;
if (selector != null) {
return Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
}
}
I want to use it like this...:
$("div").innerHTML='It works!';
...not like this...:
$("div")[0].innerHTML='It works only on the specified index!';
...or this:
for(i=0;i<$('div');i++) {
$("div")[i].innerHTML='It works great but it's ugly!';
}
This is as close as I got. I would like chaining to work and for it to be compatible with native methods:
if(!Array.prototype.innerHTML) {
Array.prototype.innerHTML = function(html) {
for (var i = 0; i < this.length; i++) {
this[i].innerHTML = html;
}
}
}
$("div").innerHTML('It works, but it ruins method chaining!');
I decided to build this engine to better learn JavaScript; It's working but I am hoping I can learn some more from the kind members of Stack Overflow. Any help would be much appreciated!
I want to use it like this...:
$("div").innerHTML='It works!';
...not like this...:
$("div")[0].innerHTML='It works only on the specified index!';
It sounds like you want to have assigning to innerHTML on your set of results assign to the innerHTML of all of the results.
To do that, you'll have to use a function, either directly or indirectly.
Directly:
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
rv.setInnerHTML = setInnerHTML;
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").setInnerHTML("The new HTML");
There, we define a function, and we assign it to the array you're returning as a property. You can then call that function on the array. (You might want to use Object.defineProperty if it's available to set the setInnerHTML property, so you can make it non-enumerable.)
Indirectly (requires an ES5-enabled JavaScript engine):
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
Object.defineProperty(rv, "innerHTML", {
set: setInnerHTML
});
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").innerHTML = "The new HTML";
There, we use Object.defineProperty to define a setter for the property.
In the comments below you say
I have a few prototypes that work when individually attached to the $ function. Example: $('div').makeClass('this'); They do not work when they are chained together. Example: $('div').makeClass('this').takeClass('that');
To make chaining work, you do return this; from each of the functions (so the end of makeClass would do return this;). That's because when you're chaining, such as obj.foo().bar(), you're calling bar on the return value of foo. So to make chaining work, you make sure foo returns this (the object on which foo was called).
This is what works; it's a slightly different syntax then I gave in my prior example, but the end result is the same. I had some great help from other Stack Exchange members, thanks again everyone.
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(), node = node || document.body;
if (selector != null) {
return Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
}
}
if(!Array.prototype.html) {
Array.prototype.html = function(html) {
for (var i = 0; i < this.length; i++) {
this[i].innerHTML = html;
}
return this; //<---- Silly me, my original code was missing this.
}
}
When I run it, everything (including chaining) works as desired:
$("div").html('hello world');
OUTPUT:
<div>hello world</div>
Cheers!

Javascript chaining and variable substitute

I am trying to get javascript chaining to work using variable substitution. Not able to get it work. Help appreciated.
var Class = function() {
this.one = function() {
alert('one');
return this;
}
this.two = function() {
alert('two');
return this;
}
if (this instanceof Class) {
return this.Class;
} else {
return new Class();
}
}
var test = new Class();
// this works
test.one().two();
var func = '.one().two()';
// want to make this work
test[func];
there is no function with the name '.one().two()'
Try this,
test['one']()['two']();
Edit:
I believe you are using this for learning purpose only and not on production site.
Highly not recommended. You might want to try an array instead:
var funcs = ['one','two'];
for(var i = 0; i < funcs.length; i++) {
test[funcs[i]]();
}
you can then wrap this into a little function:
function callChain(obj, funcs)
{
for(var i = 0; i < funcs.length; i++) {
obj[funcs[i]]();
}
return obj;
}
Edit: If your chain is stored as a string: .one().two(), you can use the split & string functions to generate the array dynamically.
Well, what you are asking for is far from best practice - so I will give you an unpopular answer - use eval.
If your input is general code as string, you don't really have any other option (specifically when your functions have parameters - .one(1 + 0.5).two(new Date())).
For example, to your Class, add:
this.excecute = function(commands){
eval('this' + commands);
};
And then:
test.excecute('.one().two(4 * 5)');
Working example: http://jsbin.com/ipazaz/1/edit
This emits the warning "eval is evil" (jslint, I think) - but I do not believe functions can be evil.
Even worse, what if you had the string 'one(); two(4 * 5);'?
You can make that work as well, using with:
this.excecute = function(commands){
with(this){
eval(commands);
}
};
This has an extra warning: "Don't use 'with'" - They really have something against us today, don't they?
Working example: http://jsbin.com/ipazaz/2/edit
Thank you all for prompt help. I ended up settling upon Ben Rowe suggestion.
var funcs = ['one','two'];
for(var i = 0; i < funcs.length; i++) {
test[funcs[i]]();
}
It fitted my requirement nicely. Appreciate all for the help. You all are wonderful.
You could add a method to the constructor:
this.chain = function chain(){
if (arguments.length && /\./.test(arguments[0])) {
return chain.apply(this,arguments[0].split('.'));
}
var methods = [].slice.call(arguments),
method = methods.shift();
if(this[method] instanceof Function){
this[method].call(this);
}
if (methods.length){
chain.apply(this,methods);
}
return this;
}
// now you could do something like:
test.chain('one.two.one.two.two');
Or extend Object.prototype
Object.prototype.chain = function chain(){
if (arguments.length && /\./.test(arguments[0])) {
return chain.apply(this,arguments[0].split('.'));
}
var methods = [].slice.call(arguments),
method = methods.shift();
if(this[method] && this[method] instanceof Function){
this[method].call(this);
}
if (methods.length){
chain.apply(this,methods);
}
return this;
};
// usage
({one:function(){console.log('I am one');},
two:function(){console.log('I am two');}})
.chain('one.two.one.one.two.two.two.one.two');
I think a simpler approach is to use javascript's array reduce function.
I needed this for some dynamic jquery stuff I was writing. Once you have your array of chain-able methods you could easily do the following.
var methods = ['next', 'child', 'parent'];
var element = methods.reduce(function(method){
return $(selector)[method]();
});
console.log(element) //works! as all method names in methods array are applied and returned each iteration.
For my case the accepted answer did not work for me it seems to only return the passed obj and not the obj plus it's chained methods.

Categories

Resources