js array search function for ie8 - javascript

I've written a js lib that needs to work in ie8 and I've been asked not to use jQuery as part of the implementation. Part of the js lib requires searching an array for a matching value. Modern browsers support the array indexOf() function which will accomplish this. However, since my js lib needs to support ie8 I won't be able to use this function. Initially I wrote the following custom function:
function inArray(anArray, aValue)
{
for (var i = 0; i < anArray.length; i++)
if (anArray[i] === aValue) return true;
//value was not in array
return false;
}
However, this morning it occured to me that it would be better to write this using prototypal inheritance. What would be a good way to rewrite this using prototypal inheritance? Also, is there a way I can go into the direct source code used for the ES standard, copy the indexOf() function and paste it into my custom js lib? Not sure if this is possible or not but it seems like a good way to port snippets without reinventing the wheel.

You're probably best off with a utility function you pass the array into, such as the inArray in your question.
You could add a shim for Array#indexOf or includes or similar to Array.prototype, but if you did, it would become enumerable and show up in for-in loops. People shouldn't use for-in to loop through arrays, but sadly, they sometimes do. If they do in your codebase or any library your codebase includes, that will be a problem.
Unfortunately, you can't make it non-enumerable because IE8 doesn't support Object.defineProperty (except on HTML elements, oddly).

As a general rule, having your own namespace and using a function like you've described is probably better for a library, something like this:
MyLib.inArray = function(array, value) {
// implementation here
};
You could modify the prototype of Array with the ES6 function .includes() like so:
Array.prototype.includes = Array.prototype.includes || function(needle) {
// implementation here
};
and then you can use it like so:
[1, 2, 3].includes(3); // true
(Note that if it already exists, we don't override it)
However, this is generally bad practice to do in a library, because you're modifying a reference to a build-in function that other scripts on the page may rely on! Additionally, properties added this way will show up when iterating the array with for..in, which is extremely undesirable.

Related

How to make a slice function closer to the native one? In the form in which invoked? [duplicate]

Google JavaScript Style Guide advises against extending the Array.prototype.
However, I used Array.prototype.filter = Array.prototype.filter || function(...) {...} as a way to have it (and similar methods) in browsers where they do not exist. MDN actually provides similar example.
I am aware about Object.prototype issues, but Array is not a hash table.
What issues may arise while extending Array.prototype that made Google advise against it?
Most people missed the point on this one. Polyfilling or shimming standard functionality like Array.prototype.filter so that it works in older browsers is a good idea in my opinion. Don't listen to the haters. Mozilla even shows you how to do this on the MDN. Usually the advice for not extending Array.prototype or other native prototypes might come down to one of these:
for..in might not work properly
Someone else might also want to extend Array with the same function name
It might not work properly in every browser, even with the shim.
Here are my responses:
You don't need to use for..in on Array's usually. If you do you can use hasOwnProperty to make sure it's legit.
Only extend natives when you know you're the only one doing it OR when it's standard stuff like Array.prototype.filter.
This is annoying and has bit me. Old IE sometimes has problems with adding this kind of functionality. You'll just have to see if it works in a case by case basis. For me the problem I had was adding Object.keys to IE7. It seemed to stop working under certain circumstances. Your mileage may vary.
Check out these references:
http://perfectionkills.com/extending-native-builtins/
http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
https://github.com/kriskowal/es5-shim
Good luck!
I'll give you the bullet points, with key sentences, from Nicholas Zakas' excellent article Maintainable JavaScript: Don’t modify objects you don’t own:
Dependability: "The simple explanation is that an enterprise software product needs a consistent and dependable execution environment to be maintainable."
Incompatible implementations: "Another peril of modifying objects that you don’t own is the possibility of naming collisions and incompatible implementations."
What if everyone did it?: "Simply put: if everyone on your team modified objects that they didn’t own, you’d quickly run into naming collisions, incompatible implementations, and maintenance nightmares."
Basically, don't do it. Even if your project is never going to be used by anyone else, and you're never going to import third party code, don't do it. You'll establish a horrible habit that could be hard to break when you start trying to play nice with others.
As a modern update to Jamund Ferguson's answer:
Usually the advice for not extending Array.prototype or other native prototypes might come down to one of these:
for..in might not work properly
Someone else might also want to extend Array with the same function name
It might not work properly in every browser, even with the shim.
Points 1. and 2. can now be mitigated in ES6 by using a Symbol to add your method.
It makes for a slightly more clumsy call structure, but adds a property that isn't iterated over and can't be easily duplicated.
// Any string works but a namespace may make library code easier to debug.
var myMethod = Symbol('MyNamespace::myMethod');
Array.prototype[ myMethod ] = function(){ /* ... */ };
var arr = [];
// slightly clumsier call syntax
arr[myMethod]();
// Also works for objects
Object.prototype[ myMethod ] = function(){ /* ... */ };
Pros:
For..in works as expected, symbols aren't iterated over.
No clash of method names as symbols are local to scope and take effort to retrieve.
Cons:
Only works in modern environments
Slightly clunky syntax
Extending Array.prototype in your own application code is safe (unless you use for .. in on arrays, in which case you need to pay for that and have fun refactoring them).
Extending native host objects in libraries you intend others to use is not cool. You have no right to corrupt the environment of other people in your own library.
Either do this behind an optional method like lib.extendNatives() or have [].filter as a requirement.
Extending Natives and Host Objects
Prototype does this. It's evil. The following snippet demonstrates how doing so can produce unexpected results:
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
<script language="javascript">
a = ["not", "only", "four", "elements"];
for (var i in a)
document.writeln(a[i]);
</script>
The result:
not only four elements function each(iterator, context) { var index = 0; . . .
and about 5000 characters more.
I want to add an additional answer that allows extending the Array prototype without breaking for .. in loops, and without requiring use of hasOwnPropery:
Don't use this bad approach which causes prototype values to appear in for .. in:
Array.prototype.foo = function() { return 'foo'; };
Array.prototype.bar = function() { return 'bar'; };
let a = [ 1, 2, 3, 4 ];
console.log(`Foo: ${a.foo()}`);
console.log(`Bar: ${a.bar()}`);
console.log('==== Enumerate: ====');
for (let v in a) console.log(v);
Instead use Object.defineProperty, with enumerable: false - it exists for pretty much exactly this reason!
Object.defineProperty(Array.prototype, 'foo', {
value: function() { return 'foo'; },
enumerable: false
});
Object.defineProperty(Array.prototype, 'bar', {
value: function() { return 'bar'; },
enumerable: false
});
let a = [ 1, 2, 3, 4 ];
console.log(`Foo: ${a.foo()}`);
console.log(`Bar: ${a.bar()}`);
console.log('==== Enumerate: ====');
for (let v in a) console.log(v);
Note: Overall, I recommend avoiding enumerating Arrays using for .. in. But this knowledge is still useful for extending prototypes of classes where enumeration is appropriate!
Some people use for ... in loops to iterate through arrays. If you add a method to the prototype, the loop will also try to iterate over that key. Of course, you shouldn't use it for this, but some people do anyway.
You can easily create somekind of sandbox with poser library.
Take a look on https://github.com/bevacqua/poser
var Array2 = require('poser').Array();
// <- Array
Array2.prototype.eat = function () {
var r = this[0];
delete this[0];
console.log('Y U NO .shift()?');
return r;
};
var a = new Array2(3, 5, 7);
console.log(Object.keys(Array2.prototype), Object.keys(Array.prototype))
I believe this question deserves an updated ES6 answer.
ES5
First of all, as many people have already stated. Extending the native prototypes to shim or polyfill new standards or fix bugs is standard practice and not harmful. For example if a browser doesn't support the .filter method if (!Array.prototype.filter) you are free to add this functionality on your own. In-fact, the language is designed to do exactly this to manage backwards compatibility.
Now, you'd be forgving for thinking that since JavaScript object use prototypal inheritance, extending a native object like Array.prototype without interfering should be easy, but up until ES6 it's not been feasible.
Unlike objects for example, you had to rely and modifying the Array.prototype to add your own custom methods. As others have pointed out, this is bad because it pollutes the Global namespace, can interfere with other code in an unexpected way, has potential security issues, is a cardinal sin etc.
In ES5 you can try hacking this but the implementations aren't really practically useful. For more in depth information, I recommend you check out this very informative post: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
You can add a method to an array, or even an array constructor but you run into issues trying to work with the native array methods that rely on the length property. Worst of all, these methods are going to return a native Array.prototype and not your shiny new sub-class array, ie: subClassArray.slice(0) instanceof subClassArray === false.
ES6
However, now with ES6 you can subclass builtins using class combined with extends Array that overcomes all these issues. It leaves the Array.prototype intact, creates a new sub-class and the array methods it inherits will be of the same sub-class! https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
See the fiddle below for a demonstration:
https://jsfiddle.net/dmq8o0q4/1/
Extending the prototype is a trick that only works once. You do and you use a library that also does it (in an incompatible way) and boom!
The function you are overriding could be used by the internal javascript calls and that could lead to unexpected results. Thats one of the reasons for the guideline
For example I overrode indexOf function of array and it messed up accessing array using [].

How can I make a sub-function for a pre-existing data type? [duplicate]

I was working on an AJAX-enabled asp.net application.
I've just added some methods to Array.prototype like
Array.prototype.doSomething = function(){
...
}
This solution worked for me, being possible reuse code in a 'pretty' way.
But when I've tested it working with the entire page, I had problems..
We had some custom ajax extenders, and they started to behave as the unexpected: some controls displayed 'undefined' around its content or value.
What could be the cause for that? Am I missing something about modifing the prototype of standart objects?
Note: I'm pretty sure that the error begins when I modify the prototype for Array. It should be only compatible with IE.
While the potential for clashing with other bits o' code the override a function on a prototype is still a risk, if you want to do this with modern versions of JavaScript, you can use the Object.defineProperty method, e.g.
// functional sort
Object.defineProperty(Array.prototype, 'sortf', {
value: function(compare) { return [].concat(this).sort(compare); }
});
Modifying the built-in object prototypes is a bad idea in general, because it always has the potential to clash with code from other vendors or libraries that loads on the same page.
In the case of the Array object prototype, it is an especially bad idea, because it has the potential to interfere with any piece of code that iterates over the members of any array, for instance with for .. in.
To illustrate using an example (borrowed from here):
Array.prototype.foo = 1;
// somewhere deep in other javascript code...
var a = [1,2,3,4,5];
for (x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'
}
Unfortunately, the existence of questionable code that does this has made it necessary to also avoid using plain for..in for array iteration, at least if you want maximum portability, just to guard against cases where some other nuisance code has modified the Array prototype. So you really need to do both: you should avoid plain for..in in case some n00b has modified the Array prototype, and you should avoid modifying the Array prototype so you don't mess up any code that uses plain for..in to iterate over arrays.
It would be better for you to create your own type of object constructor complete with doSomething function, rather than extending the built-in Array.
What about Object.defineProperty?
There now exists Object.defineProperty as a general way of extending object prototypes without the new properties being enumerable, though this still doesn't justify extending the built-in types, because even besides for..in there is still the potential for conflicts with other scripts. Consider someone using two Javascript frameworks that both try to extend the Array in a similar way and pick the same method name. Or, consider someone forking your code and then putting both the original and forked versions on the same page. Will the custom enhancements to the Array object still work?
This is the reality with Javascript, and why you should avoid modifying the prototypes of built-in types, even with Object.defineProperty. Define your own types with your own constructors.
There is a caution! Maybe you did that: fiddle demo
Let us say an array and a method foo which return first element:
var myArray = ["apple","ball","cat"];
foo(myArray) // <- 'apple'
function foo(array){
return array[0]
}
The above is okay because the functions are uplifted to the top during interpretation time.
But, this DOES NOT work: (Because the prototype is not defined)
myArray.foo() // <- 'undefined function foo'
Array.prototype.foo = function(){
return this[0]
}
For this to work, simply define prototypes at the top:
Array.prototype.foo = function(){
return this[0]
}
myArray.foo() // <- 'apple'
And YES! You can override prototypes!!! It is ALLOWED. You can even define your own own add method for Arrays.
You augmented generic types so to speak. You've probably overwritten some other lib's functionality and that's why it stopped working.
Suppose that some lib you're using extends Array with function Array.remove(). After the lib has loaded, you also add remove() to Array's prototype but with your own functionality. When lib will call your function it will probably work in a different way as expected and break it's execution... That's what's happening here.
Using Recursion
function forEachWithBreak(someArray, fn){
let breakFlag = false
function breakFn(){
breakFlag = true
}
function loop(indexIntoSomeArray){
if(!breakFlag && indexIntoSomeArray<someArray.length){
fn(someArray[indexIntoSomeArray],breakFn)
loop(indexIntoSomeArray+1)
}
}
loop(0)
}
Test 1 ... break is not called
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
})
Produces
a
b
c
d
e
f
g
Test 2 ... break is called after element c
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
if(element =="c"){breakFn()}
})
Produces
a
b
c
There are 2 problems (as mentioned above)
It's enumerable (i.e. will be seen in for .. in)
Potential clashes (js, yourself, third party, etc.)
To solve these 2 problems we will:
Use Object.defineProperty
Give a unique id for our methods
const arrayMethods = {
doSomething: "uuid() - a real function"
}
Object.defineProperty(Array.prototype, arrayMethods.doSomething, {
value() {
// Your code, log as an example
this.forEach(v => console.log(v))
}
})
const arr = [1, 2, 3]
arr[arrayMethods.doSomething]() // 1, 2, 3
The syntax is a bit weird but it's nice if you want to chain methods (just don't forget to return this):
arr
.map(x=>x+1)
[arrayMethods.log]()
.map(x=>x+1)
[arrayMethods.log]()
In general messing with the core javascript objects is a bad idea. You never know what any third party libraries might be expecting and changing the core objects in javascript changes them for everything.
If you use Prototype it's especially bad because prototype messes with the global scope as well and it's hard to tell if you are going to collide or not. Actually modifying core parts of any language is usually a bad idea even in javascript.
(lisp might be the small exception there)

Why is .reduce used instead of reduce()? In flattening an array of arrays with JavaScript

This example is from http://eloquentjavascript.net/code/#5.1.
My question is the first bullet-pointed detail; others may be helpful details, but are additional; also see the first short program to see my question in context.
- Why is arrays.reduce() used instead of reduce(arrays()). I know that their's works with the arrays.reduce, but why?
This is an answer to a comment that is useful, but additional to the original question.
My question is with this first program. Since it uses arrays.reduce,
reduce would be a method of arrays, I am not sure why reduce is a
method of arrays. The reason might be in the design decisions of
JavaScript? Thanks, #cookie monster, for that comment!
This is the program with the context of my question-
var arrays = [[1, 2, 3], [4, 5], [6]];
console.log(arrays.reduce(function(flat, current) {
return flat.concat(current);
}, []));
// → [1, 2, 3, 4, 5, 6]
These next details are additional, but may(or may not) be of use:
I know that the [] at the end is used because it is the start parameter in the function reduce so that the other arrays are added to that empty array. I know the .concat is putting together the two arrays like + with strings, but for arrays. Here is what the reduce function, even though it is standard, looks like:
function reduce(array, combine, start){
var current = start;
for(var i = 0; i < array.length; i++)
current = combine(current, array[i]);
return current;
}
One of their other examples showed my way with a single array, if that helps. It looked like:
console.log(reduce([1, 2, 3, 4], function(a, b){
return a + b;
}, 0));
// 10
Thanks! :)
In object oriented design, a guiding principle is that you create or declare objects and those objects have a series of methods on them that operate on that particular type of object. As Javascript is an object oriented language, the built-in functions follow many of the object oriented principles.
.reduce() is a function that operates only on Arrays. It is of no use without an Array to operate on. Thus, in an object oriented design paradigm, it makes complete sense to place the .reduce() function as a method on an Array object.
This object-oriented approach offers the following advantages vs. a global reduce() function:
It is consistent with the object oriented principles used elsewhere in the language.
It is convenient to invoke the .reduce() function on a particular array by using array.reduce() and it is obvious from the syntax which array it is operating on.
All array operations are grouped as methods on the Array object making the API definition more self documenting.
If you attempt to do obj.reduce() (invoke it on a non-array), you will immediately get an runtime error about an undefined .reduce() method.
No additional space is taken in the global scope (e.g. no additional global symbol is defined - lessening the chance for accidental overwrite or conflict with other code).
If you want to know why anyone ever used a global reduce() instead, you would need to understand a little bit about the history of Javascript evolution. Before ES5 (or for users running browsers who hadn't yet implemented ES5 like IE8), Javascript did not have a built-in .reduce() method on the Array object. Yet, some developers who were familiar with this type of useful iteration capability from other languages wanted to to use it in their own Javascript or in their own Javascript framework.
When you want to add some functionality to an existing built-in object like Array in Javascript, you generally have two choices. You can add a method to the prototype (in object-oriented fashion) or you can create a global function that takes the Array as its first argument.
For the Array object in particular, there are some potential issues with adding iterable methods to the Array prototype. This is because if any code does this type of iteration of an array (a bad way to iterate arrays, but nevertheless done by many):
for (var prop in array)
they will end up iterating not only the elements of the array, but also any iterable properties of the array. If a new method is assigned to the prototype with this type of syntax:
Array.prototype.myMethod = function() {}
Then, this new method will end up getting iterated with the for (var prop in array) syntax and it will often cause problems.
So, rather than adding a new method to the prototype, a safer alternative was to just use a global function and avoid this issue.
Starting in ES 5.1, there is a way using Object.defineProperty() to add non-iterable methods to an object or prototype so for newer browsers, it is now possible to add methods to a prototype that are not subject to the problem mentioned above. But, if you wanted to support older browsers (like IE8) and use reduce() type of functionality, you're still stuck with these ancient limitations.
So ... even though a global reduce() is less object oriented and is generally not as desirable in Javascript, some older code went that route for legitimate safety/interoperability reasons. Fortunately, we are putting that road behind us as old version of IE drop off in usage (thank god for Microsoft dropping XP support to finally accelerate the demise of old versions of IE). And newer browsers already contain array.reduce() built in.
JavaScript was/is influenced by the language Scheme, a dialect of Lisp. In Scheme higher order functions are a key component/feature of the language. In fact the reduce function is pretty much equivalent to the fold function in Scheme. In the case of the reduce function in JavaScript, the creators of the language noticed that programmers often need to traverse arrays in a certain fashion, and gave programmers a higher order function where they can pass in a function to specify how they want to manipulate the data. Having higher order functions allows programmers to abstract redundant code therefore creating shorter, cleaner, more readable code.
You can use the reduce function in JavaScript to do many things other than flatten lists. Look here an example.

Array check followed by forEach()

Now that I'm programming in javascript more and more often, there's a task I'm coming across quite often that I wonder could be dealt with more elegantly.
It's about checking whether a variable, values say, is an array of Xs, or rather just an X, immediatly followed by an iteration over it or its elements.
(X being object, string, number, ... anything really -- except array).
Especially when dealing with xml or json files, a single X is not wrapped in [ ] to make it a 1-element array, and my code breaks if I don't watch out.
I deal with this now in the following way:
if (!(values instanceof Array)) values = [values]
values.forEach(function(value){/*do stuff with value*/});
For now, I've written a function to take care of this,
function arrayIfNot(arr) {return (arr instanceof Array) ? arr : [arr];}
Which I can use as
arrayIfNot(values).forEach(function(value){/*do stuff with value*/});
but as it is such a common task, I'd be surprised if there isn't a common shortcut or library function (jQuery?) to do this.
Thanks!
EDIT:
I suppose I could extend the prototypes like so (haven't tried):
Array.prototype.toArray = function () {return this;};
String.prototype.toArray = function () {return [this];};
...
so that I could do
values.toArray().forEach(function(value){/*do stuff with value*/});
but I'm always warned against extending the prototype. What do you think?
Thanks again!
Personally, I've adopted this idiom:
[].concat(a)
This takes advantage of the behavior of concat, which is that if its argument is a scalar, it just adds it to the array; if it is an array, it adds each of its elements.
There is a common way to do this in modern browsers, it's Array.isArray, and it's supported from IE9 and up.
MDN has a polyfill for non-supporting browsers.
jQuery has it's own version, jQuery.isArray
For your specific example, a common way to do it is
values = Array.isArray(values) ? values : [values];
If you're willing to use a library, Underscore.js has a lot of fantastic additions to basic JavaScript. Using Underscore, I commonly do something like this:
function myFunction(arg) {
arrayArg = _.flatten([arg])
}
If your arg might itself contain arrays which you need to preserve, just add true as a second argument to flatten.

Why does document.querySelectorAll return a StaticNodeList rather than a real Array?

It bugs me that I can't just do document.querySelectorAll(...).map(...) even in Firefox 3.6, and I still can't find an answer, so I thought I'd cross-post on SO the question from this blog:
http://blowery.org/2008/08/29/yay-for-queryselectorall-boo-for-staticnodelist/
Does anyone know of a technical reason why you don't get an Array? Or why a StaticNodeList doesn't inherit from an Array in such a way that you could use map, concat, etc?
(BTW if it's just one function you want, you can do something like NodeList.prototype.map = Array.prototype.map;...but again, why is this functionality (intentionally?) blocked in the first place?)
You can use ES2015 (ES6) spread operator:
[...document.querySelectorAll('div')]
will convert StaticNodeList to Array of items.
Here is an example on how to use it.
[...document.querySelectorAll('div')].map(x => console.log(x.innerHTML))
<div>Text 1</div>
<div>Text 2</div>
I believe it to be a philosophical decision of the W3C. The design of the W3C DOM [spec] is quite orthogonal to the design of JavaScript, as the DOM is meant to be platform and language neutral.
Decisions like "getElementsByFoo() returns an ordered NodeList" or "querySelectorAll() returns a StaticNodeList" are very much intentional, so that implementations don't have to worry about aligning their returned data structure based on language-dependent implementations (like .map being available on Arrays in JavaScript and Ruby, but not on Lists in C#).
The W3C aim low: they'll say a NodeList should contain a readonly .length property of type unsigned long because they believe every implementation can at least support that, but they won't say explicitly that the [] index operator should be overloaded to support getting positional elements, because they don't want to stymie some poor little language that comes along that wants to implement getElementsByFoo() but cannot support operator overloading. It's a prevalent philosophy present throughout much of the spec.
John Resig has voiced a similar option as yours, to which he adds:
My argument isn't so much that
NodeIterator isn't very DOM-like it's
that it isn't very JavaScript-like. It
doesn't take advantage of the features
present in the JavaScript language and
use them to the best of its ability...
I do somewhat empathize. If the DOM was written specifically with JavaScript features in mind it would be a lot less awkward and more intuitive to use. At the same time I do understand the W3C's design decisions.
I don't know why it returns a node list instead of an array, maybe because like getElementsByTagName it will update the result when you update the DOM. Anyway a very simple method to transform that result in a simple array is:
Array.prototype.slice.call(document.querySelectorAll(...));
and then you can do:
Array.prototype.slice.call(document.querySelectorAll(...)).map(...);
Just to add to what Crescent said,
if it's just one function you want, you can do something like NodeList.prototype.map = Array.prototype.map
Don't do this! It's not at all guaranteed to work.
No JavaScript or DOM/BOM standard specifies that the NodeList constructor-function even exists as a global/window property, or that the NodeList returned by querySelectorAll will inherit from it, or that its prototype is writable, or that the function Array.prototype.map will actually work on a NodeList.
A NodeList is allowed to be a ‘host object’ (and is one, in IE and some older browsers). The Array methods are defined as being allowed to operate on any JavaScript ‘native object’ that exposes numeric and length properties, but they're not required to work on host objects (and in IE, they don't).
It's annoying that you don't get all the array methods on DOM lists (all of them, not just StaticNodeList), but there's no reliable way round it. You'll have to convert every DOM list you get back to an Array manually:
Array.fromList= function(list) {
var array= new Array(list.length);
for (var i= 0, n= list.length; i<n; i++)
array[i]= list[i];
return array;
};
Array.fromList(element.childNodes).forEach(function() {
...
});
Array.from(document.querySelectorAll(...)).map(...)
Not available on IE11 though https://caniuse.com/mdn-javascript_builtins_array_from
I think you can simply do following
Array.prototype.map.call(document.querySelectorAll(...), function(...){...});
It works perfect for me
This is an option I wanted to add to the range of other possibilities suggested by others here. It's meant for intellectual fun only and is not advised.
Just for the fun of it, here's a way to "force" querySelectorAll to kneel down and bow to you:
Element.prototype.querySelectorAll = (function(QSA){
return function(){
return [...QSA.call(this, arguments[0])]
}
})(Element.prototype.querySelectorAll);
Now it feels good to step all over that function, showing it who's the boss.
Now I don't know what's better, creating a whole new named function wrapper and then have all your code use that weird name (pretty much jQuery-style) or override the function like above once so the rest of your code would still be able to use the original DOM method name querySelectorAll.
Such approach would eliminate possible use of sub-methods
I wouldn't recommend this in any way, unless you honestly don't give a [you know what].

Categories