2009-02-21 10 views
24

Estoy tratando de extender el método Array.push para que al usar push desencadene un método de devolución de llamada, luego realice la función de matriz normal.Cómo extender Array.prototype.push()?

No estoy muy seguro de cómo hacer esto, pero aquí hay un código con el que he estado jugando sin éxito.

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

    //callback method goes here 

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

} 

arr.push('test'); 

Respuesta

62

Dado que el comando push permite insertar más de un elemento, utilizo la variable de argumentos a continuación para permitir que el método real push tenga todos los argumentos.

Esta solución sólo afecta a la variable arr:

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

Esta solución afecta a todas las matrices. No te recomiendo que hagas eso.

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

Mi forma preferida de envoltura de funciones es pasar Array.prototype.push cuando ejecuta su función externa y aceptarla en la función como la variable original. Es un poco más conciso – pottedmeat

+9

@pottedmeat: pero es menos legible. Recuerde, los programas no solo están escritos para la máquina, ¡sino también para otros programadores! – Christoph

+1

@some ¡Muchas gracias por una explicación clara del prototipo y no! – Dorjan

4

Usted puede hacerlo de esta manera:

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

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

Si estás en una situación sin llamada, también se puede ir por esta solución:

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; 
} 

Editar:

Mientras te estoy diciendo cómo hacerlo, es posible que te sirva mejor si usas un método diferente que realiza la devolución de llamada y solo llama a pu sh en la matriz en lugar de presionar sobre todo. Puede terminar con algunos efectos secundarios inesperados. Por ejemplo, push parece ser varadica (toma una cantidad variable de argumentos, como printf), y usar lo anterior lo rompería.

Tendría que hacer un lío con _Arguments() y _ArgumentsLength() para anular correctamente esta función. Sugiero altamente en contra de esta ruta.

Editar una vez más: O podría usar "argumentos", eso funcionaría también. Sin embargo, desaconsejamos tomar esta ruta.

+0

Array.prototype.push.call (esto, los datos); no funcionará ya que Array puede tomar múltiples elementos. Array.prototype.push.apply (esto, argumentos); – ToughPal

-1

Me gustaría hacer esto:

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

Si quería ser un argumento para una devolución de llamada, usted puede hacer esto:

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

Estos dos han sido probados.

+1

@cdmckay: Si lo hubieras probado, te habrías dado cuenta de que tienes un bucle infinito creado ... – some

+0

@alguno Malo, escribí eso anoche. Los he reparado y probado. – cdmckay

+1

@cdmckay: Ahora funciona, pero usted contamina el espacio de nombre global con 'original', y si alguna otra función cambia el valor de 'original', ha roto la inserción de la matriz. Su segunda solución no tiene sentido: si debo proporcionar la devolución de llamada cuando presiono, puedo llamar a la devolución de llamada yo mismo. – some

4

Array.prototype.push se introdujo en JavaScript 1.2. Es realmente tan simple como esto:

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

Siempre podría agregar algo al frente de eso.

0

que quería llamar una función después el objeto ha sido empujado a la matriz, así que hice lo siguiente:

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

primer lugar usted necesita subclase Array:

ES6: (no compatible con Babel o navegador que no sea Chrome50 + ahora https://kangax.github.io/compat-table/es6/)

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

ES5 :(proto está casi en desuso pero es la única solución para ahora)

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

Curioso por qué estás agregando una respuesta a una pregunta que tiene más de 7 años. – Geuis

+1

¿Curioso por qué alguien no lo haría? JS ha cambiado. – pat

Cuestiones relacionadas