0

Update

Thanks for your help guys, I was unaware of the things to be aware of when using lambda (fat arrow) functions.

if (window.Array && !Array.prototype.isEmpty)
{
 Array.prototype.isEmpty = function ()
 {
  return this.length === 0;
 };
}

console.log("[]", [].isEmpty());
console.log("[1]", [1].isEmpty());

This works now.


Original Question

I have been trying to add the functionality of isEmpty to the Array prototype in javascript to both make my code a little cleaner and also because I want to learn how to do it properly.

I understand that it is advisable to not add your own methods to the existing objects and to make your own, but at this point, I really want to figure out where I am going astray.

I also understand that you can test for an empty array by just doing array.length === 0.

I have been running into issues where my this is referring to the window object instead of the calling array.

This is my code

if (window.Array && !Array.prototype.isEmpty)
{
    Array.prototype.isEmpty = (callback, thisArg) =>
    {
     return this.length === 0;
    };
}

console.log("[]", [].isEmpty());
console.log("[1]", [1].isEmpty());

Because this is a reference to the window object, this.length is false so no matter what array is calling it, this function returns true.

How do I get this to refer to the calling object instead of window?

I based on this forEach shim for NodeList, I had tried to change my isEmpty function to emulate it because I saw that the forEach was using a callback and my shim wasn't.

NodeList.forEach shim:

if (window.NodeList && !NodeList.prototype.forEach)
{
    NodeList.prototype.forEach = (callback, thisArg) =>
    {
        thisArg = thisArg || window;
        for (let i = 0; i < this.length; i++)
        {
            callback.call(thisArg, this[i], i, this);
        }
    };
}

Seeing that, this is what I tried to change my function to

if (window.Array && !Array.prototype.isEmpty)
{
    Array.prototype.isEmpty = (callback, thisArg) =>
    {
        thisArg = thisArg || window;
        callback.call(thisArg, this.length === 0, 0, this);
    };
}

console.log("[]", [].isEmpty());
console.log("[1]", [1].isEmpty());

Unfortunately, this results in an error as the callback function is not defined, I was hoping to send an empty function.

The difference between the two functions is that in the NodeList.forEach this is a reference to the NodeList that is invoking forEach instead of a reference to window.

From what I can tell, the difference, in the code, between the working NodeList.forEach and my failing Array.isEmpty is that with forEach you supply it with a function to act on it, but with isEmpty it's just an empty function call.

I will admit that I don't understand callback functions as well as I would like so I am flailing a bit here. I have tried looking up implementations of isEmpty for JS but most of the responses are just use array.length === 0, while I will agree this is a good solution, I am trying to push my knowledge boundaries.

Thank you for any insight you can give.

Samuel
  • 574
  • 3
  • 7
  • 22
  • 3
    Don't use a fat arrow function, their `this` behaviour is precisely what distinguishes them from `function` functions. – deceze Nov 22 '17 at 21:03
  • 1
    It is bad practice to add to prototype functions to native JS objects. Mainly because those may become a standard in the future and they may not do what your code did. – Intervalia Nov 22 '17 at 21:03
  • 3
    To expand on @Intervalia, when such a function exists it can become "okay" practice, it's called a polyfill. In that case just do your damn best to match the spec as closely as possible. Anyway, basic functions can just be basic functions `isEmpty = (arg) => {}` – René Nov 22 '17 at 21:07
  • Yeah, 100% don't add this on the prototype. If you have an array and want to check, just use a normal function and pass the array as the argument. The only time it is okay to put something on the prototype is if it is a Javascript-standard function that is not present on some older version of the language, and usually if that is the case you're using an existing polyfill, not writing your own thing anyway. – loganfsmyth Nov 22 '17 at 23:10

0 Answers0