web-dev-qa-db-fra.com

Façons d'étendre l'objet Array en javascript

j'essaie d'étendre l'objet Array en JavaScript avec des méthodes conviviales comme Array.Add () à la place Array.Push (), etc.

j'implémente 3 façons de faire cela . malheureusement, la 3ème façon ne fonctionne pas et je veux demander pourquoi? et comment le faire fonctionner.

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

de la 3ème manière, je veux étendre l'objet Array en interne classe Array3 . Comment faire cela afin de ne pas obtenir "Push n'est pas une fonction" et "indéfini"?

Ici j'ajoute une 4ème voie.

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

Là encore, je dois utiliser prototype . J'espérais éviter d'utiliser des lignes supplémentaires en dehors du constructeur de classe comme Array4.prototype .Je voulais avoir une classe définie compacte avec toutes les pièces au même endroit. Mais je pense que je ne peux pas le faire autrement.

38
demosthenes

Les noms de méthodes doivent être en minuscules. Le prototype ne doit pas être modifié dans le constructeur.

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

dans CoffeeScript

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

Si vous n'aimez pas cette syntaxe et que vous DEVEZ l'étendre à partir du constructeur, Votre seule option est:

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

   });
};

Tu pourrais aussi faire ça

ArrayExtenstions = {
   Add: function() {

   }
}
extend(ArrayExtenstions, Array.prototype);



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

Autrefois, 'prototype.js' avait une méthode Class.create. Vous pouvez envelopper tout cela est une méthode comme ça

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

    },    
    Add: function() {

    }
});

Pour plus d'informations à ce sujet et sur la mise en œuvre, consultez le code source de 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

Utilisation de __proto__

(ancienne réponse, non recommandée, peut causer des problèmes de performances )

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

Vous pouvez maintenant ajouter vos méthodes à SubArray

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

Initialiser comme des tableaux normaux

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

Se comporte comme des tableaux normaux

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

Il y a quelque temps, j'ai lu le livre Javascript Ninja écrit par John Resig , le créateur de jQuery . Fondamentalement, seul length est requis. 

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'

Je ne veux pas dire que c'est bon ou mauvais. C'est une façon originale de faire des opérations Array. L'avantage est que vous ne prolongez pas le Array prototype. N'oubliez pas que obj est un object ordinaire, ce n'est pas un Array. Par conséquent, obj instanceof Array renverra false. Pensez obj comme une façade.

Si ce code vous intéresse, lisez l'extrait Listing 4.10 Simulation de méthodes de type tableau.

2
roland

Dans votre troisième exemple, vous créez simplement une nouvelle propriété nommée prototype pour l'objet Array3. Lorsque vous faites new Array3 qui devrait être new Array3(), vous instanciez cet objet dans la variable list3. Par conséquent, la méthode Add ne fonctionnera pas car this, qui est l'objet en question, n'a pas de méthode valide Push. J'espère que tu as compris.

Edit: Check out Comprendre le contexte JavaScript pour en savoir plus sur this.

2
elclanrs

Essayez-vous de faire quelque chose de plus compliqué, puis ajoutez simplement un alias pour "Push" appelé "Ajouter"?

Sinon, il serait probablement préférable d'éviter de le faire. La raison pour laquelle je suggère que c'est une mauvaise idée est que, comme Array est un type JavaScript intégré, sa modification entraînera pour tous les scripts Array de type votre nouvelle méthode "Ajouter". Les risques de conflits de noms avec une autre tierce partie sont élevés et le script de cette tierce partie pourrait perdre sa méthode au profit de la vôtre.

Ma règle générale est de créer une fonction d'assistance pour travailler sur le tableau s'il n'existe pas déjà quelque part et d'étendre le tableau s'il est extrêmement nécessaire.

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

La solution est une solution de contournement compacte qui fonctionne comme prévu dans tous les navigateurs associés.

0
Neni

Vous NE POUVEZ PAS étendre l'objet Array en JavaScript. 

Au lieu de cela, vous pouvez définir un objet contenant une liste de fonctions exécutées sur le tableau, injecter ces fonctions dans cette instance de tableau et renvoyer cette nouvelle instance. Ce que vous ne devriez pas faire, c'est changer le Array.prototype pour inclure vos fonctions personnalisées dans la liste. 

Exemple:

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

Juste un exemple de code, vous pouvez le modifier et l'utiliser comme vous le souhaitez. Mais le concept sous-jacent que je vous recommande de suivre reste le même. 

0
Boopathi Rajaa

Vous pouvez également utiliser cette méthode dans ES6:

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

Résultat:

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