Ways to extend Array object in javascript

2019-01-21 21:54发布

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.

8条回答
霸刀☆藐视天下
2楼-- · 2019-01-21 22:23

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

查看更多
叼着烟拽天下
3楼-- · 2019-01-21 22:31

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.

查看更多
Fickle 薄情
4楼-- · 2019-01-21 22:32
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.

查看更多
够拽才男人
5楼-- · 2019-01-21 22:36

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.

查看更多
做自己的国王
6楼-- · 2019-01-21 22:39

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.

查看更多
Viruses.
7楼-- · 2019-01-21 22:43

ES6

class SubArray extends Array {
    constructor(...args) { 
        super(...args); 
    }
    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
查看更多
登录 后发表回答