As a bit outside my normal articles, I wanted to share some of the native Javascript array capabilities that can be mimicked in Salesforce Marketing Cloud Server-side Javascript. Now, for many this may not be super useful as it is a good amount of effort to get this to work correctly, but there is a lot of great capabilities and such that can come from this and is extremely useful for those coming from a client-side Javascript background to help them get some of that functionality back.

Some of these methods or capabilities are also native in SSJS, but some require a polyfill in order for it to work. Others are native, but give completely wrong results which can be greatly confusing. For these, I created their own section that also includes the polyfill to get the capability to work correctly.

Before we jump into sharing the polyfills and code examples, we should explore what a polyfill is and how we can use it in our scripts as it is very important for understanding how to implement the unsupported methods.

What Is A Polyfill?

Polyfill is a piece of code (or plugin) that provides the technology that you, the developer, expect the browser to provide natively. (Source: Remy Sharp) Basically this is creating a method or function in JS to replace what is, on the majority, native functionality, but due to the available JS version/library/translator it is not available. Think of it as using spackle to fill in a hole in a wall so it is smooth enough for you to paint on (more on this in the below quote).

So, now that we know what it is, why the heck is it called a polyfill? That is certainly a unique name…I mean why not just call it a back fill or shim? Well, author Remy Sharp wrote a book called Introducing HTML5 back in 2009 and came up with the term to help express what it would do better then other words or phrases.

Polyfill just kind of came to me, but it fitted my requirements. Poly meaning it could be solved using any number of techniques – it wasn’t limited to just being done using JavaScript, and fill would fill the hole in the browser where the technology needed to be. It also didn’t imply “old browser” (because we need to polyfill new browser too).

Also for me, the product Polyfilla (spackling in the US) is a paste that can be put in to walls to cover cracks and holes. I really liked that idea of visualising how we’re fixing the browser. Once the wall is flat, you can paint as you please or wallpaper to your heart’s content.

Remy Sharp

Now that we know what a polyfill is and why it is called polyfill, lets jump into how to use them.

How Do I Use These Polyfills?

There are a couple different approaches to enter the polyfills in. There is the inline option where you place it inside the page itself and then there is also the option to pull this in from a content block. Regardless of the way you call it in, unlike custom functions, you need to place these polyfills at the top above any calls of the capability.

Sample of inline use of polyfill:

<script runat=server>
  Platform.Load("Core","1.1.1");

    Array.prototype.some = function(func) {
      for (i = 0; i < this.length; i++) {
        check = func(this[i]);
        ret = (check) ? true : false;
      }
      return ret;
    };

    var ages = [3, 10, 18, 20];

    function checkAdult(age) {
      return age >= 18;
    }

    Write(ages.some(checkAdult));
</script>

As you can see the polyfill Array.prototype.some (line 4 to 16) is at the top of the script. If it was not above the call of ages.some() (line 18), which is the calling of the some function on our array, ages, then this would throw an error saying that expecting object: some as the method some on the Array Object would not be defined yet.

Next is the second approach, which pulls from a Content Block:

Content Block content:

<script runat=server>
  Array.prototype.some = function(func) {
    for (i = 0; i < this.length; i++) {
      check = func(this[i]);
      ret = (check) ? true : false;
    }
    return ret;
  };
</script>

IMPORTANT NOTE: if you do not include the open/close script tags in the content block, then it will not work as it will be returned as a string.

As you can see, this moved the entire polyfill into the Content Block, removing it from the inline declaraion shown in the previous example. Now that we made the content block containing the polyfill, let us explore how we would use it in our final environment:

<script runat=server>
  Platform.Load("Core","1.1.1");
    Platform.Function.ContentBlockByKey("arraySome")

    var ages = [3, 10, 18, 20];

    function checkAdult(age) {
      return age >= 18;
    }

    Write(ages.some(checkAdult));
</script>

By using the ContentBlock call, you will have the script run in the content block meaning it is now available for use in the rest of the script after it. As a note, if you did not include the script tags in your content block, you can do a sort of hacky way to still get it to work by changing the ContentBlock call to the below:

TreatAsContent('<script runat=server>' + Platform.Function.ContentBlockByKey("arraySome") + '</script>')

By appending and prepending the script tags and concatting them together in a TreatAsContent function, it will mimic as if you included the script tags inside the content block.

Now that we have an understanding of what a polyfill is and how to use it, we can move forward into the array capabilities now, Before exploring the ones that require a polyfill, let’s first review the easier ones that are also native in SSJS. From there we then move into the more complex ones that require extra effort to have work correctly.

Native Array Capabilities

Below is a list of each of the capabilities that can be used natively in SFMC SSJS without the need for a polyfill or anything. As a note, which really applies to all of these, please pay attention to each one used as there have been times where there has been odd behavior on what is an otherwise fully functioning native capability. SSJS is run through JINT, a javascript interpretor over top of .NET, so it is not a pure copy of Javascript. Also as a note, I believe it is a much older version of JINT from the early 2000s or maybe even earlier so it is even more ‘quirky’ than normal.

As a note as well, I am not going into details around using the method or capability, mostly just giving a general overview and example syntax. There are plenty of resources out there to give you details on each one if you want. For example, the MDN documentation is a great source.

Now without further ado, please see the functions and details below:

array.valueOf

this capability returns the array. It is not exactly super useful as it is essentially the same as just calling the array as itself as it is the default method of the Array Object. It will not change the original array and contains no parameters.

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var v = fruits.valueOf();
//Output: ["Banana", "Orange", "Apple", "Mango"]

array.unshift

Unshift adds new items to the beginning of an array and returns new length. This is similar to push(), but is adding to the beginning instead of the end of an array.

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon","Pineapple");
//Output: 6
//fruits = ["Lemon","Pineapple","Banana", "Orange", "Apple", "Mango"]

array.toString

toString takes the array and turns it into a comma delimited string.

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var x = fruits.toString();
//Output: "Banana", "Orange", "Apple", "Mango"

array.sort

sorts the elements of an array

IMPORTANT NOTE: that in SSJS, this requires the function below to work properly (can adjust for asc vs desc)

  • using default .sort() will cause errors in SSJS.
 var array = [40, 100, 1, 5, 25, 10];

 array.sort(function(x, y) {
  if (x < y) {
    return -1;
  }
  if (x > y) {
    return 1;
  }
  return 0;
 });
//Output: [1,5,10,25,40,100]

array.slice

returns the selected elements in an array as a new array object.

  • selects the elements starting at the given start argument, and ends at, but does not include, the given end argument.
  • the original array will not be changed

Parameter Description:

start (Optional): An integer that specifies where to start the selection (The first element has an index of 0). Use negative numbers to select from the end of an array. If omitted, it acts like “0”

end (Optional): An integer that specifies where to end the selection. If omitted, all elements from the start position and to the end of the array will be selected. Use negative numbers to select from the end of an array

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3);
//Output: ["Orange","Lemon"]

array.shift

removes the first element of an array

  • The return value of the shift method is the removed item.
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.shift();
//Output: ["Orange", "Apple", "Mango"]

array.reverse

reverses the current order of the elements in an array

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.reverse();
//Output: ["Mango","Apple","Orange","Banana"]

array.push

adds a new element to the array at the end

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi");
//Output: ["Banana", "Orange", "Apple", "Mango","Kiwi"]

array.prototype

allows you to add new properties to the Array() method

  • When constructing a property, ALL arrays will be given the property, and its value, as default.
  • When constructing a method, ALL arrays will have this method available.
  • Array.prototype does not refer to a single array, but to the Array() object itself.
  • Prototype is a global object constructor which is available for all JavaScript objects.
Array.prototype.myUcase = function() {
  for (i = 0; i < this.length; i++) {
    this[i] = this[i].toUpperCase();
  }
};

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.myUcase();
//Output: ["BANANA", "ORANGE", "APPLE", "MANGO"]

array.pop

removes the last element of an array

  • returns Any type, representing the removed array item.
 var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.pop();
//Output: ["Banana","Orange","Apple"]

array.length

returns number representing the number of elements in the array

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var len = fruits.length;
//Output: 4

array.join

turns array into string and can optionally set separator. Default is comma

  • this method will not change the original array.
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var energy = fruits.join("|");
//Output: Banana|Orange|Apple|Mango

Unexpected Results From Native Usage

These next two can be used natively without any errors, but what they do or return is not at all what should be returned or done. This unexpected behavior can lead to massive confusion or incorrect logic or scripting and is a big deal. I make special mention of these above all others as they always return incorrect results where as others it is only in some very niche instances it may not be fully correct.

array.lastIndexOf

returns the last index of matching element in array

IMPORTANT NOTE: this needs a polyfill in order to work correctly as natively it just returns -1 (no match) every time

  • Can include second parameter to designate starting index Returns -1 if no match

Polyfill:

  Array.prototype.lastIndexOf = function(val,startIndex) {
    if(!startIndex) { startIndex = 0;}
    for(i=startIndex;i<this.length;i++){
       if (this[i] == val){ret = i}
    }
    if(!ret) { ret = -1 }
    return ret;
  }

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango","Apple"];
var a = fruits.lastIndexOf("Apple");
Write(a)
//Output: 4

array.splice

adds/removes elements to/from an array and returns the removed items

  • this needs a polyfill in order to work correctly

IMPORTANT NOTE: If you do not use the polyfill, what it does is just take the elements you have in splice that you want to add and instead replaces the existing elements starting from the left side. It completely ignores the first two parameters completely.

Parameter Description:

index (Required): An integer that specifies at what position to add/remove items, Use negative values to specify the position from the end of the array

howmany (Optional): The number of items to be removed. If set to 0, no items will be removed

item1, …, itemX (Optional): The new item(s) to be added to the array

Polyfill:

Array.prototype.splice = function(startIndex, numItems){
var array = this;
var endIndex = startIndex + numItems;var itemsBeforeSplice = []; // array till startIndex
var splicedItems = []; // removed items array
var itemsAfterSplice = []; // array from endIndex

for( var i = 0; i < array.length; i++ ){
    if( i < startIndex ){ itemsBeforeSplice.push( array[i] ); } 
    if( i >= startIndex && i < endIndex ){ splicedItems.push( array[i] ); }
    if( i >= endIndex ){ itemsAfterSplice.push( array[i] ); }      
}

// Insert all arguments/parameters after numItems
for(var i = 2;i < arguments.length; i++){
  itemsBeforeSplice.push(arguments[i]);
}

// Combine before/after arrays
var remainingItems = itemsBeforeSplice.concat( itemsAfterSplice );

// Rewrite array
for(var i = 0, len=Math.max( array.length, remainingItems.length ); i < len; i++ ){
  if( remainingItems.length > i ){
    array[i] = remainingItems[i];
  } else {
    array.pop();
  }
}
return array;
}

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");
//Output: ["Banana", "Orange", "Lemon", "Kiwi", "Apple", "Mango"]

Requires A Polyfill

The below methods and capabilities require a polyfill in order to work. Attempting to use these without the polyfill will throw an error and break your script. As shown above, please remember to include the polyfill at the top of the script or at least above the first call of the method or capability.

array.some

checks if any elements in array pass a test (provided function)

  • executes the function once for each element present in the array:
  • If it finds an array element where the function returns a true value, some() returns true (and does not check the remaining values)
  • Otherwise it returns false
  • does not execute the function for array elements without values.
  • does not change the original array.

Polyfill:

Array.prototype.some = function(func) {
  for (i = 0; i < this.length; i++) {
    check = func(this[i]);
    ret = (check) ? true : false;
  }
  return ret;
};

Example:

var ages = [3, 10, 18, 20];

function checkAdult(age) {
  return age >= 18;
}

  Write(ages.some(checkAdult));
//Output: true

array.reduce

reduces the array to a single value via a ‘reducer’ function

  • this needs a Reducer Function’ to work

Polyfill:

Array.prototype.reduce = function(f,initVal) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = !initVal ? 0 : initVal;
    for(i=0;i<this.length;i++) {
      a = f(a,this[i])
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Reducer Function:

can have 4 arguments:

  • Accumulator
  • Current Value
  • Current Index (optional)
  • Source Array (optional)
function getSum(total, num) {
  return total + num;
}

Example:

var numbers = [65, 44, 12, 4];
var newarray = numbers.reduce(getSum,5)

Write(Stringify(newarray));

function getSum(total, num) {
  return total + num;
}
//Output: 130

array.reduceRight

reduces the array to a single value via a ‘reducer’ function from Right to Left instead of default Left to Right

  • this needs a Reducer Function’ to work

Polyfill:

Array.prototype.reduceRight = function(f,initVal) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = !initVal ? 0 : initVal;
    for(i= (this.length-1); i>=0 ;i--) {
      a = f(a,this[i])
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Reducer Function:

can have 4 arguments:

  • Accumulator
  • Current Value
  • Current Index (optional)
  • Source Array (optional)
function getSum(total, num) {
  return total + num;
}

Example:

var numbers = [65, 44, 12, 4];
var newarray = numbers.reduceRight(getSum,5)

Write(Stringify(newarray));

function getSum(total, num) {
  return total + num;
}
//Output: 125

array.of

creates array from declared delimited string

Polyfill:

  Array.of = function() {
   var vals = [];
   for(prop in arguments){
       vals.push(arguments[prop]);
   }
   vals.pop() //removes the "function" element at end of returned array
   return vals;
 }

Example:

var checker = Array.of(1,2,3,5,6)
//Output [1,2,3,5,6]

array.map

returns new array with results after running function on each element

  • This will only work with a function being passed in

Polyfill:

Array.prototype.map = function(f) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = [];
    for(i=0;i<this.length;i++) {
      a.push(f(this[i]))
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Example:

var numbers = [65, 44, 12, 4];
var newarray = numbers.map(myFunction)

Write(Stringify(newarray));

function myFunction(num) {
  return num * 10;
}
//Output: [650, 440, 120, 40]

Map that can return array of values from an array of objects:

var arr = [ { x: 22 }, { x: 42 } ]
var array = arr.map(objParse)
Write(Stringify(array));

function objParse(obj){
    for(prop in obj){ 
        var val = obj[prop] 
    } 
    return val;
}
//Output: [22,42]
//If your objects have more than one property, you will need to adjust the function to account for this

array.isArray

determines if an object is an array

Polyfill:

Array.isArray = function(arg) {
   return Object.prototype.toString.call(arg) === '[object Array]';
};

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var isArr = Array.isArray(fruits);
//Output: true

array.indexOf

returns the index of a matching element

  • Can include second parameter to designate starting index Returns -1 if no match

Polyfill:

  Array.prototype.indexOf = function(val,startIndex) {
    if(!startIndex) { startIndex = 0;}
    for(i=startIndex;i<this.length;i++){
       if (!ret && this[i] == val){ret = i}
    }
    if(!ret) { ret = -1 }
    return ret;
  }

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");
Write(a)
//Output 2

array.includes

returns true or false if the value is included inside of the array

Polyfill:

  Array.includes = function(val,arr) {
    for(i=0;i<arr.length;i++){
       if (!ret || ret == false){ret = val == arr[i] ? true: false;}
    }
    return ret;
  }

Example:

var arr = ["Emil", "Tobias", "Linus"];
var checker = Array.includes("Emil",arr)
//Output: true

array.forEach

calls a function for each element inside array in order

  • This will only work with a function being passed in

PolyFill:

Array.prototype.forEach = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      f(this[i])       
    }
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Example:

var sum = 0;
var numbers = [65, 44, 12, 4];
numbers.forEach(myFunction);

function myFunction(item) {
  sum += item;
  Write(sum + '<br>');
}
//Output:
//65
//109
//121
//125

array.findIndex

finds the index of the first element that meets the set criteria

  • This will only work with functions passed that return true/false

Polyfill:

Array.prototype.findIndex = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { 
          a = i; 
          break; 
      }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Example:

var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
var result = words.findIndex(function(word){return word.length > 6})
Write(Stringify(result));
//Output: 3

array.find

finds the first element that meets the set criteria

  • This will only work with functions passed that return true/false

Polyfill:

Array.prototype.find = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { 
          a = this[i]; 
          break; 
      }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Example:

var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
var result = words.find(function(word){return word.length > 6})
Write(Stringify(result));
//Output: exuberant

array.filter

filters an array and returns only those values that match filter

  • This will only work with functions passed that return true/false

Polyfill:

Array.prototype.filter = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a = [];
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { a.push(this[i]) }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Example:

var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
var filtered = words.filter(function(word){return word.length > 6})
Write(Stringify(filtered));
//Output: ["exuberant","destruction","present"]

array.fill

changes all elements in array to static value (optional start and end index)

Polyfill:

Array.prototype.fill= function(val, startIndex,endIndex) {
  if(!endCount || endIndex > this.length ) { endIndex = this.length }
  if(!startIndex) { startIndex = 0}
  for (i=0;i< (endIndex-startIndex);i++) {
    this[startIndex + i] = val
  }
  return this;
}

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango", "Kiwi", "Papaya"];
fruits.fill("Peep",0,2);
debugWrite(fruits)
//Output: ["Peep", "Peep", "Banana", "Orange", "Kiwi", "Papaya"]

array.entries

returns iterations of key/value pairs in array

Polyfill:

   Array.prototype.entries = function() {
       var k = 0, o = this;
       return {
          next: function(){
           return k < o.length ?
               {value: [k,o[k++]], done: false} :
               {done: true};
          }
       };
   };

Example:

  • as (x of y) is not available, you will need to find other ways to output, like:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var f = fruits.entries();
for (i=0;i<fruits.length;i++) {
  Write(Stringify(f.next().value) + '<br>');
}
//Outputs: 
[0, "Banana"]
[1, "Orange"]
[2, "Apple"]
[3, "Mango"]

array.copyWithin

copies an existing element in an array and replaces another specified element

Polyfill:

Array.prototype.copyWithin = function(copyIndex,startIndex,endCount) {
  if(!endCount) { endCount = 1 }
  for (i=0;i<endCount;i++) {
    this[copyIndex + i] = this[startIndex + i]
  }
  return this;
}

Example:

var fruits = ["Banana", "Orange", "Apple", "Mango", "Kiwi", "Papaya"];
fruits.copyWithin(2, 0, 2);
//Output: ["Banana", "Orange", "Banana", "Orange", "Kiwi", "Papaya"]

array.concat

combines array 1 with array 2

Polyfill:

  Array.concat = function(arr1,arr2) {
   for(i=0;i<arr2.length;i++){
       arr1.push(arr2[i]);
   }
   return arr1;
 }

Example:

var hege = ["Cecilie", "Lone"];
var stale = ["Emil", "Tobias", "Linus"];
var checker = Array.concat(hege,stale)
//Output: ["Cecilie", "Lone", "Emil", "Tobias", "Linus"]

That is all the methods and capabilities for this article! I tried to include the majority, with a focus on the most useful – but as there are so many out there, I did not get to include them all. For some too, the polyfill requires other methods that also require polyfills so I left those out to remove any inception-like confusions. A lot of these polyfills can be found individually by searching on the interwebs, but I wanted to try and gather them all in a single place. Hopefully you find this useful!

Extra For Those That Made It To The End

If you were so inclined to want to include all the polyfills so you can just reference this content from a single place, I am going to first show you how to reference it via a Code Resource, in case you want to have it universal, as I already showed how to reference via a content block. Then I will share the full polyfill ‘library’ that you can call in at the top of your scripts. As a note, this is going to add weight to your code and potentially could cause some minor performance issues so use it wisely.

Example Call:

var pageContent = HTTP.Get("https://myTSE.pub.sfmc-content.com/myPageURL")

TreatAsContent('<script runat=server>' + pageContent.Content + '</script>')

Polyfill ‘Library’:

   Array.concat = function(arr1,arr2) {
    for(i=0;i<arr2.length;i++){
        arr1.push(arr2[i]);
    }
    return arr1;
  }
                                
Array.prototype.copyWithin = function(copyIndex,startIndex,endCount) {
  if(!endCount) { endCount = 1 }
  for (i=0;i<endCount;i++) {
    this[copyIndex + i] = this[startIndex + i]
  }
  return this;
}

   Array.prototype.entries = function() {
       var k = 0, o = this;
       return {
          next: function(){
           return k < o.length ?
               {value: [k,o[k++]], done: false} :
               {done: true};
          }
       };
   };
                              
Array.prototype.fill= function(val, startIndex,endIndex) {
  if(!endCount || endIndex > this.length ) { endIndex = this.length }
  if(!startIndex) { startIndex = 0}
  for (i=0;i< (endIndex-startIndex);i++) {
    this[startIndex + i] = val
  }
  return this;
}

                                        
Array.prototype.filter = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a = [];
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { a.push(this[i]) }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

             
Array.prototype.find = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { 
          a = this[i]; 
          break; 
      }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Array.prototype.findIndex = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      if (f(this[i]) == true) { 
          a = i; 
          break; 
      }
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Array.prototype.forEach = function(c) {
  if (c && {}.toString.call(c) === '[object Function]') {
    f = c;
    var a;
    for(i=0;i<this.length;i++) {
      f(this[i])       
    }
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

  Array.includes = function(val,arr) {
    for(i=0;i<arr.length;i++){
       if (!ret || ret == false){ret = val == arr[i] ? true: false;}
    }
    return ret;
  }

  Array.prototype.indexOf = function(val,startIndex) {
    if(!startIndex) { startIndex = 0;}
    for(i=startIndex;i<this.length;i++){
       if (!ret && this[i] == val){ret = i}
    }
    if(!ret) { ret = -1 }
    return ret;
  }

 Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
};

  Array.prototype.lastIndexOf = function(val,startIndex) {
    if(!startIndex) { startIndex = 0;}
    for(i=startIndex;i<this.length;i++){
       if (this[i] == val){ret = i}
    }
    if(!ret) { ret = -1 }
    return ret;
  }

Array.prototype.map = function(f) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = [];
    for(i=0;i<this.length;i++) {
      a.push(f(this[i]))
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

   Array.of = function() {
    var vals = [];
    for(prop in arguments){
        vals.push(arguments[prop]);
    }
    vals.pop() //removes the "function" element at end of returned array
    return vals;
  }

Array.prototype.reduce = function(f,initVal) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = !initVal ? 0 : initVal;
    for(i=0;i<this.length;i++) {
      a = f(a,this[i])
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Array.prototype.reduceRight = function(f,initVal) {
  if (f && {}.toString.call(f) === '[object Function]') {
    var a = !initVal ? 0 : initVal;
    for(i= (this.length-1); i>=0 ;i--) {
      a = f(a,this[i])
    }
    return a;
  } else {
     return {"Error": "Filter provided is not a function"};
  }
}

Array.prototype.some = function(func) {
  for (i = 0; i < this.length; i++) {
    check = func(this[i]);
    ret = (check) ? true : false;
  }
  return ret;
};

Array.prototype.splice = function(startIndex, numItems){
var array = this;
var endIndex = startIndex + numItems;var itemsBeforeSplice = []; // array till startIndex
var splicedItems = []; // removed items array
var itemsAfterSplice = []; // array from endIndex

for( var i = 0; i < array.length; i++ ){
    if( i < startIndex ){ itemsBeforeSplice.push( array[i] ); } 
    if( i >= startIndex && i < endIndex ){ splicedItems.push( array[i] ); }
    if( i >= endIndex ){ itemsAfterSplice.push( array[i] ); }      
}

// Insert all arguments/parameters after numItems
for(var i = 2;i < arguments.length; i++){
  itemsBeforeSplice.push(arguments[i]);
}

// Combine before/after arrays
var remainingItems = itemsBeforeSplice.concat( itemsAfterSplice );

// Rewrite array
for(var i = 0, len=Math.max( array.length, remainingItems.length ); i < len; i++ ){
  if( remainingItems.length > i ){
    array[i] = remainingItems[i];
  } else {
    array.pop();
  }
}
return array;
}
}    

Hope you enjoy! As always let me know any mistakes or errors you may find here. Pobody’s Nerfect!

Tags: , , , , , , , , , , ,
Subscribe
Notify of
guest
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Loveraj Joshi
Loveraj Joshi
2 years ago

Yours blogs are really insightful always. Love to read yours blogs always new learning.

Cameron B
Cameron B
1 year ago

Great post, very useful. I’m working on a set of “import” libraries (using a similar technique that I’ve seen you suggest on SO). Polyfills are a perfect fit for one of those libraries.

I did notice several issues, thought I’d share. I haven’t tested all of these so I don’t know if there were any other issues I might have missed. I’ll share anything else I find.

Issues:
– concat, includes, and isArray are attempting to modify the Array type rather than the Array.prototype.
– in Array.prototype.forEach you defined var a;, but never use it.
– (this is a nitpick) The errors returned are all the same: “Filter provided is not a function”. But these anonymous functions aren’t all filters, you also have reducers, indexers, and what I’d call “multiplexers”. It’s just a bit muddied.

Cameron B
Cameron B
Reply to  Cameron B
4 months ago

I realized a little bit after I submitted, my first issue is not an issue, but as intended. Those methods are meant to attach to the type rather than the prototype.