2018-07-04

Understanding JavaScript Iteration with C#

javascript, csharp

banner

As I was chatting, someone from Coding Blocks slack channel (#javascript) has asked a question regarding a code snippet

https://gist.github.com/dance2die/1c0f3799d371c2c4bdaf1603ed32f228

His question was "Kinda lost in the [].filter.call , etc part."

I will show you a C# code snippet to explain "why" someone used call instead of directly calling filter.

๐Ÿ”จ Code Breakdown - uniqueInOrder

uniqueInOrder returns a distinct list of array for an order array with duplicate values.

Given an array [1, 1, 2, 2, 2, 3, 3, 3, 3], uniqueInOrder returns [1, 2, 3].

https://codesandbox.io/embed/w0mp565v75

But couldn't you have just used Array#filter?

https://codesandbox.io/embed/moowx3ynqx

Yes it works but [].filter.call can handle objects not derived from Array.

๐Ÿง What do you mean?

Some objects are iterable and not derived from Array. Refer to this, How I learned to Stop Looping and Love the Iterator post by Kushan for details.

The (notoriously) notable one is NodeList, which is returned by document.querySelectorAll.

๐Ÿคทย So What?

filter is defined by Array prototype thus an object calling "filter" should implement an Array prototype. But NodeList doesn't implement Array prototype, so you can't call filter on it even though it's iterable.

[].filter.call lets you use the filter method without having to convert non-Array sequences into an array. Therefore making "uniqueInOrder" method more generic.

Here is an example.

  • document.querySelectorAll('a') returns an object of type NodeList.

  • When you try to call filter directly, it fails.

  • You can get around it by using a spread syntax.

  • And [].filter.call works as well.

document queryselctorall example document queryselctorall example

๐Ÿณ C# Analogy

If you use C#, you might have run into IEnumerable<T>. It's an interface, which enables implementing class to be iterable.

Let's see two methods that accepts an iterable object of type string and prints each element.

Demo: https://dotnetfiddle.net/Widget?Languages=CSharp&CSharp_FiddleId=CBCHVu

If you were to pass wordArray to ListPrintWords, it will fail to compile while GenericPrintWords is happy to work with it.

Argument Error

๐Ÿ˜€ What did we learn?

So [].filter.call can be used to deal with any iterable objects that do not inherit Array prototypes.

And it's roughly equivalent to dealing with objects implementing IEnumerable<T> interface in .NET, thus enabling methods accept any kind of generic iterable sequences.

๐Ÿ‘‹ Parting Words

I've had hard time understanding the WHY of such a method initially. I am able to see more when I make analogies to languages I am used to (C#).

Functional Programming (FP) in JavaScript is being adopted nowadays (Redux, Functional Light JS by Kyle Simpson), thus started learning Elixir to see WHY JavaScript community is raving about FP.

I'd love your feedback/errata. So leave a comment below or send me a twit :)