Open chris-morgan opened 7 years ago
If you’ve ever done this, then it probably wasn’t a good idea (and please do not use it). Extending existing DOM functionality through prototypes is often considered bad practice as this can lead to masses of issues.
This is pretty intense (probably dangerous and not recommended)
It's often not a good idea to extend the functionality of DOM through prototypes, especially in older versions of IE (article).
@AlexWayfer I am perplexed by your comment. This polyfill is already assigning to NodeList.prototype.forEach
—as a polyfill must. My suggestion is simply to use an already-existing forEach
method instead of writing a new one.
The articles you link to are uniformly out of date (spanning 2010 to 2014), and not applicable to polyfills.
Some comments specifically on the Todd Motto article you linked: it’s a terrible article. Even back in early 2014 when it was written it was by and large a bad article. Certainly, the specific thing of not defining NodeList.prototype.forEach
was reasonable back then, because it wasn’t a standard yet; now, however, it’s perfectly reasonable, because it’s a defined standard—and exactly what this polyfill is for. And using [].forEach
instead of Array.prototype.forEach
was always silly, so I agree with his fourth problem (and the part of the fifth problem which is just repeating the fourth problem). But problems one, two three, six, seven and eight and eleven were fairly ridiculous when the article was written, and now in the context of NodeList.prototype.forEach
are completely irrelevant. And as for the recommendation to write your own forEach
method—that is the height of the craziness in the article: that’s exactly what Array.prototype.forEach
is; as with most of Array
’s methods, it’s deliberately designed to be generic, and perfectly safe for application on other types with a length
property and properties matching the indexes. So writing another forEach
method is simply slowing things down further.
Ooh, one other thing I just noticed: in both Chrome and Firefox, NodeList.prototype.forEach
is actually the same function as Array.prototype.forEach
. That is, NodeList.prototype.forEach === Array.prototype.forEach
.
@chris-morgan, OK, you're right, thank you for the answer.
Then, we can use polyfill-nodelist-foreach
package with suggested by you realization.
Even simpler:
if (Array.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach;
?
@FrankConijn There are two problems with your suggestion:
Clobbering NodeList.prototype.forEach unnecessarily is bad form. If already present, it’s not necessarily the same function as Array.prototype.forEach; it’s possible that in future it may be specialised for operating more efficiently on a node list. Also, writing to such an object has a habit of slowing down JavaScript engines as they fall back to a slow path, though the difference will normally not be measurable.
There is no guarantee that NodeList
is defined; in browsers, it will be, but in other environments such as Node, it may not be. A polyfill like this is generally designed to just be a noop in other environments that don’t have a prerequisite for what is being polyfilled. (On that note, in writing window.NodeList
in my suggestion I did the wrong thing: I should indeed have written typeof NodeList != "undefined"
, because the global object is not necessarily named window
.)
@chris-morgan -- According to TJ Crowder on https://stackoverflow.com/a/46929259/2056165, after simplifying and debugging it per my suggestions, it should be:
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach;
So, he is adding && NodeList.prototype
. Would you agree that that is indeed necessary or at least useful?
Checking NodeList.prototype
is just rigour on TJ’s part—if someone had defined a global NodeList
which wasn’t a type (outrageous, but theoretically possible), that would prevent it from causing an exception. I could take it or leave it.
(It’s similar rigour that leads to using !==
instead of !=
which is sufficient in this case, given that both sides are known to be strings.)
@FrankConijn @chris-morgan what's the summary?
I recall stepping into similar trouble a while ago (server-side rendering), but we managed to walk around by hand-written polyfill.
Considering the package already gives similar functionality it seem we could include the suggestion.
Agree?
Thanks.
As far as I can tell,
Array.prototype.forEach
will function identically toNodeList.prototype.forEach
and would thus be fine onNodeList.prototype
:This simplifies and shortens the code, but introduces a dependency on Array.prototype.forEach (IE9+). But it seems implausible that one would polyfill one and not the other if caring about IE<9 (and who does, these days?), so I think it’d be reasonable to do that.