Ways to extend Array object in javascript

Posted on

Ways to extend Array object in javascript – Even if we have a good project plan and a logical concept, we will spend the majority of our time correcting errors abaout javascript and arrays. Furthermore, our application can run without obvious errors with JavaScript, we must use various ways to ensure that everything is operating properly. In general, there are two types of errors that you’ll encounter while doing something wrong in code: Syntax Errors and Logic Errors. To make bug fixing easier, every JavaScript error is captured with a full stack trace and the specific line of source code marked. To assist you in resolving the JavaScript error, look at the discuss below to fix problem about Ways to extend Array object in javascript.

Problem :

i try to extend Array object in javascript with some user friendly methods like Array.Add() instead Array.push() etc…

i implement 3 ways to do this.
unfortunetly the 3rd way is not working and i want to ask why? and how to do it work.

//------------- 1st way
Array.prototype.Add=function(element){
     this.push(element);
};

var list1 = new Array();
list1.Add("Hello world");
alert(list1[0]);

//------------- 2nd way
function Array2 () {
    //some other properties and methods
};

Array2.prototype = new Array;
Array2.prototype.Add = function(element){
  this.push(element);  
};

var list2 = new Array2;
list2.Add(123);
alert(list2[0]);

//------------- 3rd way
function Array3 () {
    this.prototype = new Array;
    this.Add = function(element){
      this.push(element);  
    };
};

var list3 = new Array3;
list3.Add(456);  //push is not a function
alert(list3[0]); // undefined

in 3rd way i want to extend the Array object internally Array3 class.
How to do this so not to get “push is not a function” and “undefined”?

Here i add a 4th way.

//------------- 4th way
function Array4 () {
    //some other properties and methods
    this.Add = function(element){
        this.push(element);
    };
 };
Array4.prototype = new Array();

var list4 = new Array4();
list4.Add(789);
alert(list4[0]);

Here again i have to use prototype.
I hoped to avoid to use extra lines outside class constructor as Array4.prototype.
I wanted to have a compact defined class with all pieces in one place.
But i think i cant do it otherwise.

Solution :

ES6

class SubArray extends Array {
    last() {
        return this[this.length - 1];
    }
}
var sub = new SubArray(1, 2, 3);
sub // [1, 2, 3]
sub instanceof SubArray; // true
sub instanceof Array; // true

Using __proto__

(old answer, not recommended, may cause performance issues)

function SubArray() {
  var arr = [ ];
  arr.push.apply(arr, arguments);
  arr.__proto__ = SubArray.prototype;
  return arr;
}
SubArray.prototype = new Array;

Now you can add your methods to SubArray

SubArray.prototype.last = function() {
  return this[this.length - 1];
};

Initialize like normal Arrays

var sub = new SubArray(1, 2, 3);

Behaves like normal Arrays

sub instanceof SubArray; // true
sub instanceof Array; // true

Method names should be lowercase. Prototype should not be modified in the constructor.

function Array3() { };
Array3.prototype = new Array;
Array3.prototype.add = Array3.prototype.push

in CoffeeScript

class Array3 extends Array
   add: (item)->
     @push(item) 

If you don’t like that syntax, and you HAVE to extend it from within the constructor,
Your only option is:

// define this once somewhere
// you can also change this to accept multiple arguments 
function extend(x, y){
    for(var key in y) {
        if (y.hasOwnProperty(key)) {
            x[key] = y[key];
        }
    }
    return x;
}


function Array3() { 
   extend(this, Array.prototype);
   extend(this, {
      Add: function(item) {
        return this.push(item)
      }

   });
};

You could also do this

ArrayExtenstions = {
   Add: function() {

   }
}
extend(ArrayExtenstions, Array.prototype);



function Array3() { }
Array3.prototype = ArrayExtenstions;

In olden days, ‘prototype.js’ used to have a Class.create method. You could wrap all this is a method like that

var Array3 = Class.create(Array, {
    construct: function() {

    },    
    Add: function() {

    }
});

For more info on this and how to implement, look in the prototype.js source code

A while ago I read the book Javascript Ninja written by John Resig, the creator of jQuery.
He proposed a way to mimic array-like methods with a plain JS object. Basically, only length is required.

var obj = {
    length: 0, //only length is required to mimic an Array
    add: function(elem){
        Array.prototype.push.call(this, elem);
    },
    filter: function(callback) {
        return Array.prototype.filter.call(this, callback); //or provide your own implemetation
    }
};

obj.add('a');
obj.add('b');
console.log(obj.length); //2
console.log(obj[0], obj[1]); //'a', 'b'

I don’t mean it’s good or bad. It’s an original way of doing Array operations. The benefit is that you do not extend the Array prototype.
Keep in mind that obj is a plain object, it’s not an Array. Therefore obj instanceof Array will return false. Think obj as a fa├žade.

If that code is of interest to you, read the excerpt Listing 4.10 Simulating array-like methods.

In your third example you’re just creating a new property named prototype for the object Array3. When you do new Array3 which should be new Array3(), you’re instantiating that object into variable list3. Therefore, the Add method won’t work because this, which is the object in question, doesn’t have a valid method push. Hope you understand.

Edit: Check out Understanding JavaScript Context to learn more about this.

You can also use this way in ES6:

Object.assign(Array.prototype, {
    unique() {
      return this.filter((value, index, array) => {
        return array.indexOf(value) === index;
      });
    }
});

Result:

let x = [0,1,2,3,2,3];
let y = x.unique();
console.log(y); // => [0,1,2,3]

Are you trying to do something more complicated then just add an alias for “push” called “Add”?

If not, it would probably be best to avoid doing this. The reason I suggest this is a bad idea is that because Array is a builtin javascript type, modifying it will cause all scripts Array type to have your new “Add” method. The potential for name clashes with another third party are high and could cause the third party script to lose its method in favour of your one.

My general rule is to make a helper function to work on the Array’s if it doesnt exist somewhere already and only extend Array if its extremely necessary.

You CANNOT extend the Array Object in JavaScript.

Instead, what you can do is define an object that will contain a list of functions that perform on the Array, and inject these functions into that Array instance and return this new Array instance. What you shouldn’t do is changing the Array.prototype to include your custom functions upon the list.

Example:

function MyArray() {
  var tmp_array = Object.create(Array.prototype);
  tmp_array = (Array.apply(tmp_array, arguments) || tmp_array);
  //Now extend tmp_array
  for( var meth in MyArray.prototype )
    if(MyArray.prototype.hasOwnProperty(meth))
      tmp_array[meth] = MyArray.prototype[meth];
  return (tmp_array);
}
//Now define the prototype chain.
MyArray.prototype = {
  customFunction: function() { return "blah blah"; },
  customMetaData: "Blah Blah",
}

Just a sample code, you can modify it and use however you want. But the underlying concept I recommend you to follow remains the same.

var SubArray = function() {                                           
    var arrInst = new Array(...arguments); // spread arguments object
    /* Object.getPrototypeOf(arrInst) === Array.prototype */
    Object.setPrototypeOf(arrInst, SubArray.prototype);     //redirectionA
    return arrInst; // now instanceof SubArray
};

SubArray.prototype = {
    // SubArray.prototype.constructor = SubArray;
    constructor: SubArray,

    // methods avilable for all instances of SubArray
    add: function(element){return this.push(element);},
    ...
};

Object.setPrototypeOf(SubArray.prototype, Array.prototype); //redirectionB

var subArr = new SubArray(1, 2);
subArr.add(3); subArr[2]; // 3

The answer is a compact workaround which works as intended in all supporting browsers.

Leave a Reply

Your email address will not be published. Required fields are marked *