2011-03-15 19 views
26

¿Hay alguna manera de saber cuándo un usuario ha presionado (mediante push()) un elemento en una matriz?Javascript: Adjuntar al oyente de eventos a la matriz para el evento Push()

Básicamente tengo un script asíncrono que permite al usuario enviar comandos a una matriz. Una vez que se carga mi script, ejecuta los comandos. El problema es que el usuario puede enviar comandos adicionales a la matriz después de que mi script ya se haya ejecutado y necesito que se lo notifique cuando esto suceda. Tenga en cuenta que esto es solo una matriz regular que el usuario crea a sí mismo. Google Analytics hace algo similar a esto.

También encontré esto, que es donde creo que Google lo hace, pero no entiendo muy bien el código: Aa = función (k) { return Object.prototype [ha] .call (Object (k)) == "[tabla de objeto]"

también se encontró un gran ejemplo que parece cubrir las bases, pero no puedo conseguir mi método de empuje adicional para que funcione correctamente: http://jsbin.com/ixovi4/4/edit

+0

¿El usuario crea esta matriz a través de una IU que está proporcionando? – joelt

+0

No, tiene que ser una matriz regular porque mi script aún no se ha cargado, por lo que no tengo ningún objeto envoltorio especial que puedan crear, etc. – KingOfHypocrites

Respuesta

21

La única manera sensata de hacer esto es escribir una clase que envuelve una matriz:

function EventedArray(handler) { 
    this.stack = []; 
    this.mutationHandler = handler || function() {}; 
    this.setHandler = function(f) { 
     this.mutationHandler = f; 
    }; 
    this.callHandler = function() { 
     if(typeof this.mutationHandler === 'function') { 
     this.mutationHandler(); 
     } 
    }; 
    this.push = function(obj) { 
     this.stack.push(obj); 
     this.callHandler(); 
    }; 
    this.pop = function() { 
     this.callHandler(); 
     return this.stack.pop(); 
    }; 
    this.getArray = function() { 
     return this.stack; 
    } 
} 

var handler = function() { 
    console.log('something changed'); 
}; 

var arr = new EventedArray(handler); 

//or 

var arr = new EventedArray(); 
arr.setHandler(handler); 


arr.push('something interesting'); //logs 'something changed' 
+0

El problema es que mi script aún no se ha cargado, por lo que tiene ser una matriz regular Cualquier objeto especial que pueda crear, no tendrán acceso cuando creen la matriz. – KingOfHypocrites

+0

También encontré esto, que es donde creo que Google lo hace, pero no entiendo muy bien el código: Aa = función (k) { return Object.prototype [ha] .call (Object (k)) == " [matriz de objetos] " – KingOfHypocrites

+0

O si tuviera una forma de convertir la matriz normal a mi tipo de objeto especial una vez que mi script esté cargado y luego adjuntar el controlador de eventos especiales. – KingOfHypocrites

0

no probado, pero estoy asumiendo que algo como esto podría funcionar:

Array.prototype.push = function(e) { 
    this.push(e); 
    callbackFunction(e); 
} 
+0

en realidad tal vez no, estaba tratando de ampliar el built in push – moe

+0

Esto es parecido a lo que necesito, pero me pregunto si hay una manera de hacerlo solo en una matriz específica o si de alguna manera podría saber la identificación de la matriz ? Conseguí que esto funcionara de alguna manera, pero no estoy seguro de cómo asegurarme de que es la matriz que realmente necesito ver: http://jsbin.com/axate5/edit – KingOfHypocrites

+0

También encontré esto, que es donde creo que Google lo hace pero no entiendo muy bien el código: Aa = function (k) { return Object.prototype [ha] .call (Object (k)) == "[objeto Array]" – KingOfHypocrites

13

probar esto:

var MyArray = function() { }; 
MyArray.prototype = []; 
MyArray.prototype.push = function() { 
    console.log('push now!'); 
    for(var i = 0; i < arguments.length; i++) { 
     Array.prototype.push.call(this, arguments[i]); 
    } 
}; 

var arr = new MyArray(); 
arr.push(2,3,'test',1); 

puede agregar funciones a después de empujar o antes de empujar

0

Mucho mejor manera es utilizar el hecho de que esos métodos modifican la longitud de la matriz. La manera de tomar ventaja de eso es bastante simple (CoffeeScript):

class app.ArrayModelWrapper extends Array 
    constructor: (arr,chName,path)-> 
    vl = arr.length 
    @.push.apply(@,arr) 
    Object.defineProperty(@,"length",{ 
     get: ->vl 
     set: (newValue)=> 
     console.log("Hello there ;)") 
     vl = newValue 
     vl 
     enumerable: false 
    }) 
3

¿Por qué no hacer algo como esto?

Array.prototype.eventPush = function(item, callback) { 
    this.push(item); 
    callback(this); 
} 

A continuación, defina un controlador.

handler = function(array) { 
    console.log(array.length) 
} 

continuación, utilizar el eventPush en el lugar que desea un evento específico ocurra que pasa en el controlador de esta manera:

a = [] 
a.eventPush(1, handler); 
a.eventPush(2, handler); 
18

Se podría utilizar un 'eventify' función que anula empuje en el pasado formación.

var eventify = function(arr, callback) { 
    arr.push = function(e) { 
     Array.prototype.push.call(arr, e); 
     callback(arr); 
    }; 
}; 

En el siguiente ejemplo, 3 alertas deben plantearse lo que es lo que hace el controlador de eventos (devolución de llamada) después eventify ha sido llamado.

var testArr = [1, 2]; 

testArr.push(3); 

eventify(testArr, function(updatedArr) { 
    alert(updatedArr.length); 
}); 

testArr.push(4); 
testArr.push(5); 
testArr.push(6); 
+2

Esta es la respuesta perfecta en el contexto dado pregunta. –

+1

Este fragmento de código genio. Gracias. –

1

Esto agregará una función llamada onPush a todas las matrices, por defecto no debe hacer nada por lo que no interfiere con el funcionamiento normal de las matrices.

simplemente anule onPush en una matriz individual.

Array.prototype.oldPush = Array.prototype.push; 
Array.prototype.push = function(obj){ 
    this.onPush(obj); 
    this.oldPush(obj); 
}; 
//Override this method, be default this shouldnt do anything. As an example it will. 
Array.prototype.onPush = function(obj){ 
    alert(obj + 'got pushed'); 
}; 

//Example 
var someArray = []; 

//Overriding 
someArray.onPush = function(obj){ 
    alert('somearray now has a ' + obj + ' in it'); 
}; 

//Testing 
someArray.push('swag'); 

Esto alerta 'somearray ahora tiene un botín en ella'

0

Si desea hacerlo en una sola matriz:

var a = []; 

a.push = function(item) { 
    Array.prototype.push.call(this, item); 
    this.onPush(item); 
}; 

a.onPush = function(obj) { 
    // Do your stuff here (ex: alert(this.length);) 
}; 
0

para propósitos de depuración que puede probar. Y rastrear la función de llamada desde la pila de llamadas.

yourArray.push = function(){debugger;} 
2

Me gustaría envolver la matriz original alrededor de una interfaz de observador simple como ese.

function EventedList(list){ 
    this.listbase = list; 
    this.events = []; 
} 

EventedList.prototype.on = function(name, callback){ 
    this.events.push({ 
     name:name, 
     callback:callback 
    }); 
} 

//push to listbase and emit added event 
EventedList.prototype.push = function(item){ 
    this.listbase.push(item); 
    this._emit("added", item) 
} 

EventedList.prototype._emit = function(evtName, data){ 
    this.events.forEach(function(event){ 
     if(evtName === event.name){ 
      event.callback.call(null, data, this.listbase); 
     } 
    }.bind(this)); 
} 

entonces me instanciarlo con una matriz de base

//returns an object interface that lets you observe the array 
    var evtList = new EventedList([]); 

    //attach a listener to the added event 
    evtList.on('added', function(item, list){ 
     console.log("added event called: item = "+ item +", baseArray = "+ list); 
    }) 

    evtList.push(1) //added event called: item = 1, baseArray = 1 
    evtList.push(2) //added event called: item = 2, baseArray = 1,2 
    evtList.push(3) //added event called: item = 3, baseArray = 1,2,3 

también se puede extender el observador observar otras cosas como prePush o postPush o lo que sea eventos desea emitir a medida que interactúan con la matriz base interna.

1

A veces es necesario hacer cola antes de que se realice una devolución de llamada. Esto resuelve ese problema. Empuje cualquier elemento (s) a una matriz. Una vez que desee comenzar a consumir estos elementos, pase la matriz y una devolución de llamada al QueuedCallback(). QueuedCallback sobrecargará array.push como devolución de llamada y luego recorrerá los elementos en cola. Continúa presionando ítems a esa matriz y se reenviarán directamente a tu devolución de llamada. La matriz permanecerá vacía.

Compatible con todos los navegadores e IE 5.5+.

var QueuedCallback = function(arr, callback) { 
    arr.push = callback; 
    while (arr.length) callback(arr.shift()); 
}; 

Uso de muestra here.

Cuestiones relacionadas