2009-02-21 11 views
24

J'essaie d'étendre la méthode Array.push de sorte que l'utilisation de push déclenche une méthode de rappel, puis exécute la fonction de tableau normal.Comment faire pour étendre Array.prototype.push()?

Je ne suis pas sûr de savoir comment faire cela, mais voici un code avec lequel j'ai joué sans succès.

arr = []; 
arr.push = function(data){ 

    //callback method goes here 

    this = Array.push(data); 
    return this.length; 

} 

arr.push('test'); 

Répondre

62

Puisque push permet de pousser plus d'un élément, j'utilise la variable arguments ci-dessous pour laisser la vraie méthode push avoir tous les arguments.

Cette solution ne concerne que la variable arr:

arr.push = function(){ 
    //Do what you want here... 
    return Array.prototype.push.apply(this,arguments); 
} 

Cette solution affecte tous les tableaux. Je ne recommande pas que vous fassiez cela.

Array.prototype.push=(function(){ 
    var original = Array.prototype.push; 
    return function() { 
     //Do what you want here. 
     return original.apply(this,arguments); 
    }; 
})(); 
+0

Ma forme préférée d'enveloppement de fonction consiste à passer Array.prototype.push lorsque vous exécutez votre fonction externe et à l'accepter dans la fonction en tant que variable originale. C'est un peu plus concis – pottedmeat

+9

@pottedmeat: mais c'est moins lisible - rappelez-vous que les programmes ne sont pas seulement écrits pour la machine, mais aussi pour d'autres programmeurs! – Christoph

+1

@some Merci beaucoup pour une explication claire du prototype et non! – Dorjan

4

Vous pouvez le faire de cette façon:

arr = [] 
arr.push = function(data) { 
    alert(data); //callback 

    return Array.prototype.push.call(this, data); 
} 

Si vous êtes dans une situation sans appel, vous pouvez aussi aller pour cette solution:

arr.push = function(data) { 
    alert(data); //callback 

    //While unlikely, someone may be using psh to store something important 
    //So we save it. 
    var saved = this.psh; 
    this.psh = Array.prototype.push; 
    var ret = this.psh(data); 
    this.psh = saved; 
    return ret; 
} 

Edit:

Pendant que je vous dis comment faire, vous pourriez être mieux servi avec l'utilisation d'une méthode différente qui effectue le rappel puis appelle seulement pu sh sur le tableau plutôt que de passer outre. Vous pouvez vous retrouver avec des effets secondaires inattendus. Par exemple, push semble être varadic (prend un nombre variable d'arguments, comme printf), et l'utilisation de ce qui précède casserait cela.

Vous auriez besoin de faire des dégâts avec _Arguments() et _ArgumentsLength() pour surcharger correctement cette fonction. Je suggère fortement contre cette route.

Modifier une fois de plus: Ou vous pourriez utiliser des "arguments", cela fonctionnerait aussi. Toujours déconseiller de prendre cette route si.

+0

Array.prototype.push.call (ce, données); ne fonctionnera pas comme Array peut prendre plusieurs éléments. Array.prototype.push.apply (this, arguments); – ToughPal

-1

je ferais ceci:

var callback = function() { alert("called"); }; 
var original = Array.prototype.push; 
Array.prototype.push = function() 
{ 
    callback(); 
    return original.apply(this, arguments); 
}; 

Si vous vouliez un argument pour un rappel, vous pouvez le faire:

var original = Array.prototype.push; 
Array.prototype.push = function(callback) 
{ 
    callback(); 
    return original.apply(this, Array.prototype.slice.call(arguments, 1)); 
} 

Ces deux ont été testés.

+1

@cdmckay: Si vous l'aviez testé, vous auriez remarqué que vous avez créé une boucle infinie ... – some

+0

@some Mon mauvais, je l'ai écrit tard hier soir. Je les ai corrigés et testés. – cdmckay

+1

@cdmckay: Maintenant cela fonctionne, mais vous polluez l'espace de nom global avec 'original', et si une autre fonction change la valeur de 'original', vous avez cassé le push du tableau. Votre deuxième solution n'a aucun sens: si je dois fournir le rappel lorsque je le pousse, je peux appeler le rappel moi-même. – some

4

Array.prototype.push a été introduit dans JavaScript 1.2. Il est vraiment aussi simple que ceci:

Array.prototype.push = function() { 
    for(var i = 0, l = arguments.length; i < l; i++) this[this.length] = arguments[i]; 
    return this.length; 
}; 

Vous pourriez toujours ajouter quelque chose à l'avant de cela.

0

Je voulais appeler une fonction après l'objet a été poussé au tableau, donc je ne les éléments suivants:

myArray.push = function() { 
    Array.prototype.push.apply(this, arguments); 
    myFunction(); 
    return myArray.length; 
}; 

function myFunction() { 
    for (var i = 0; i < myArray.length; i++) { 
     //doSomething; 
    } 
} 
1

Vous devez d'abord sous-classe Array:

ES6: (non compatible avec babel ou navigateur autre que Chrome50 + en ce moment https://kangax.github.io/compat-table/es6/)

class SortedArray extends Array { 
    constructor(...args) { 
     super(...args); 
    } 
    push() { 
     return super.push(arguments); 
    } 
} 

ES5 :(proto est presque obsolète, mais il est la seule solution pour l'instant)

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

SortedArray.prototype.push = function() { 
    this.arr.push(arguments); 
}; 
+0

Curieux pourquoi vous ajoutez une réponse à une question qui a plus de 7 ans. – Geuis

+1

Curieux pourquoi quelqu'un ne le ferait pas? JS a changé. – pat

Questions connexes