2012-06-06 14 views
5

Questo può sembrare sciocco, ma in questo giorno ed età, uno dovrebbe essere in grado di aspettarsi che JS sollevi un evento se il contenuto di di un array è stato modificato.C'è un modo per ottenere una richiamata quando il valore di un elemento dell'array è cambiato?

Sono state poste alcune domande relative alla notifica quando una variabile cambia (definire getter o setter). E sembra che ci sia a way to do that (almeno per la maggior parte dei browser tra cui IE6 +)

Il mio problema è che io sto cercando di ricevere la notifica se un elemento all'interno di un array modifiche:

var ar = ["one", "two", "three"]; 
    // setting the whole array will call the custom setter method 
    // (assuming you defined it) 

    ar = ["one", "three", "five"]; 

    // however, this will only call the getter method and won't call the setter 
    // without defining custom setters for every item in the array. 

    ar[1] = "two"; 

Ovviamente, io sono cercando di evitare di forzare il coder ad utilizzare le funzioni .getVale() e .setValue() stile java della vecchia scuola per accedere/modificare i dati.

+0

Backbone.js può attivare eventi quando i modelli di raccolta cambiano. Non proprio la stessa cosa, ma puoi vedere come lo fanno. – asawyer

+1

Si potrebbe avere la matrice come variabile privata di un oggetto, quindi l'unico modo per cambiare la variabile è utilizzare un metodo su quell'oggetto, che può generare un evento ... –

+1

Penso che dovresti leggere il [pattern osservabile] (http://jsclass.jcoglan.com/observable.html) – MilkyWayJoe

risposta

0

Ok, basata sul codice di @ David Wolever e altri commenti, non v'è in realtà una soluzione:

Utilizzare le note da John Dyer per implementare il metodo addProperty. Posizionare un setTimeout nel metodo getter da confrontare con il valore originale di un breve periodo di tempo dopo la lettura avviene:

addProperty(myObject, 'vals', 
    function() { 
     var _oldVal = "" + this._val; 
     var _parent = this; 
     console.log('getter!'); 
     setTimeout(function() { 
      var curVal = "" + _parent._val; 
      if (curVal != _oldVal) 
       console.log('array changed!'); 
     }, 200); 
     return this._val; 
    }, 
    function (value) { 
     console.log('setter!'); 
     this._val = value; 
    }); 

    myObject.vals = ["one", "two", "three"]; 
    myObject.vals[1] = "five"; 
3

In breve: no, non è possibile. Noterai che Arrays non fornisce alcun meccanismo di distribuzione degli eventi e la loro API non include alcuna funzionalità di tipo callback.

In più: come altri hanno notato, è possibile avvolgere la matrice ... ed è anche possibile interrogare gli array contenuti:

function watchArray(arr, callback) { 
    var oldVal = "" + arr; 
    setInterval(function() { 
     var curVal = "" + arr; 
     if (curVal != oldVal) { 
      callback(); 
      oldVal = curVal; 
     } 
    }, 100); 
} 

Ma questo metodo ha alcuni evidenti problemi: interroga, si' ll arrivare lento a guardare un po 'di array, ecc

+0

Grazie per questo post. Poiché il getter viene chiamato quando viene modificato un elemento dell'array e il tuo è un modo per confrontare = getter + delay + comapre = cambia notifica. Il problema lento è trovare quale elemento è cambiato (meno di un problema per me). – MandoMando

+1

E il nuovo metodo defineProperty come suggerito da @Phrogz sopra? –

0

Penso timeout soluzioni basate non sono i migliori.
Se è possibile utilizzare solo push e pop di modificare l'array, è possibile escludere push e pop metodi di Array prototipo (o solo qualche oggetto che si desidera monitorare):

var myWatchableArr = []; 
myWatchableArr.setChangeCallback = function(callback){ 
    this.changeCallback = callback; 
} 
myWatchableArr.push = function(e){ 
    Array.prototype.push.call(this,e); 
    if(typeof this.changeCallback == "function") 
     this.changeCallback(this); 
} 
myWatchableArr.push(3); 
myWatchableArr.setChangeCallback(function(arr){ 
    console.log("the array has been changed", arr); 
}); 
// now watching for changes 
myWatchableArr.push(4); 

Se push e pop non sono sufficiente, è possibile aggiungere un po 'di metodo setAt da utilizzare come myWatchableArr.setAt(3, value) anziché myWatchableArr[3]=value.

Problemi correlati