web-dev-qa-db-de.com

Möglichkeiten zum Erweitern des Array-Objekts in Javascript

ich versuche, Array-Objekt in Javascript mit einigen benutzerfreundlichen Methoden wie Array.Add () statt Array.Push () usw. zu erweitern.

ich implementiere 3 Wege, dies zu tun . Leider funktioniert der 3. Weg nicht und ich möchte fragen, warum? und wie es funktioniert.

//------------- 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

auf dritte Weise möchte ich das Array-Objekt intern erweitern Array3-Klasse . Wie mache ich das, um nicht "Push ist keine Funktion" und "undefined" zu bekommen?

Hier füge ich einen vierten Weg hinzu.

//------------- 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]);

Auch hier muss ich prototype ..__ verwenden. Ich habe gehofft, zusätzliche Zeilen außerhalb des Klassenkonstruktors als Array4.prototype ..__ zu vermeiden. Aber ich denke, ich kann es nicht anders machen.

38
demosthenes

Methodennamen sollten Kleinbuchstaben sein. Prototyp sollte im Konstruktor nicht geändert werden.

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

in CoffeeScript

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

Wenn Ihnen diese Syntax nicht gefällt, und Sie MÜSSEN sie innerhalb des Konstruktors erweitern, Ihre einzige Option ist:

// 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)
      }

   });
};

Sie könnten das auch tun

ArrayExtenstions = {
   Add: function() {

   }
}
extend(ArrayExtenstions, Array.prototype);



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

In früheren Tagen hatte 'prototype.js' eine Class.create-Methode. Sie könnten das alles so einwickeln

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

    },    
    Add: function() {

    }
});

Weitere Informationen hierzu und zur Implementierung finden Sie im Quellcode von prototype.js

28
SMathew

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

Verwenden von __proto__

(alte Antwort, nicht empfohlen, kann zu Leistungsproblemen führen )

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

Jetzt können Sie Ihre Methoden zu SubArray hinzufügen.

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

Initialisieren Sie wie bei normalen Arrays

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

Verhält sich wie normale Arrays

sub instanceof SubArray; // true
sub instanceof Array; // true
13
laggingreflex

Vor einiger Zeit las ich das Buch Javascript Ninja von John Resig , dem Ersteller von jQuery . Er schlug vor, Array-ähnliche Methoden mit einem einfachen JS-Objekt nachzuahmen. Grundsätzlich ist nur length erforderlich. 

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'

Ich meine nicht, dass es gut oder schlecht ist. Es ist eine originelle Art, Array-Operationen auszuführen. Der Vorteil ist, dass Sie den Array prototype..__ nicht erweitern. Denken Sie daran, dass obj eine einfache object ist, es ist keine Array. Deshalb gibt obj instanceof Arrayfalse zurück. Stellen Sie sich obj als Fassade vor.

Wenn dieser Code für Sie von Interesse ist, lesen Sie den Auszug Listing 4.10 Array-ähnliche Methoden simulieren.

2
roland

In Ihrem dritten Beispiel erstellen Sie nur eine neue Eigenschaft mit dem Namen prototype für das Objekt Array3. Wenn Sie new Array3 tun, der new Array3() sein soll, instantiieren Sie dieses Objekt in der Variablen list3. Daher funktioniert die Add-Methode nicht, da this, das betreffende Objekt, keine gültige Methode Push hat. Ich hoffe du verstehst.

Edit: Check out JavaScript-Kontext verstehen , um mehr über this zu erfahren.

2
elclanrs

Versuchen Sie, etwas komplizierter zu machen, als nur einen Alias ​​für "Push" mit dem Namen "Hinzufügen" hinzuzufügen?

Wenn nicht, wäre es wahrscheinlich am besten, dies zu vermeiden. Ich schlage vor, dass dies eine schlechte Idee ist, weil Array ein eingebauter Javascript-Typ ist, wenn Sie ihn modifizieren, werden alle Scripts-Array-Typen mit Ihrer neuen Methode "Hinzufügen" versehen. Das Potenzial für Namenskollisionen mit anderen Drittanbietern ist hoch und könnte dazu führen, dass das Skript eines Drittanbieters seine Methode zugunsten Ihres Skripts verliert.

Meine allgemeine Regel ist, eine Hilfsfunktion für die Arbeit mit den Arrays zu erstellen, falls diese nicht bereits vorhanden ist, und Array nur dann zu erweitern, wenn es extrem notwendig ist.

0
duyker
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

Die Antwort ist eine kompakte Problemumgehung, die in allen unterstützten Browsern wie beabsichtigt funktioniert.

0
Neni

Sie können das Array-Objekt NICHT in JavaScript erweitern. 

Stattdessen können Sie ein Objekt definieren, das eine Liste von Funktionen enthält, die für das Array ausgeführt werden, diese Funktionen in diese Array-Instanz einfügen und diese neue Array-Instanz zurückgeben. Was Sie nicht tun sollten, ist Array.prototype so zu ändern, dass Ihre benutzerdefinierten Funktionen in die Liste aufgenommen werden. 

Beispiel:

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",
}

Nur ein Beispielcode, Sie können ihn ändern und verwenden, wie Sie möchten. Das zugrunde liegende Konzept, das ich Ihnen empfehlen möchte, bleibt jedoch gleich. 

0
Boopathi Rajaa

Sie können diesen Weg auch in ES6 verwenden:

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

Ergebnis:

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