Domanda

Passando attraverso la documentazione Javascript, ho trovato i seguenti due funzioni in un oggetto JavaScript sembra interessante:

.watch - Orologi per una proprietà da assegnare un valore e esegue una funzione che si verifica quando
. .unwatch - Rimuove un watchpoint impostato con il metodo di orologio

.

Utilizzo di esempio:

o = { p: 1 };
o.watch("p", function (id,oldval,newval) {
    console.log("o." + id + " changed from " + oldval + " to " + newval)
    return newval;
});

Ogni volta che si cambia il valore della proprietà di "p", questa funzione risulta attivata.

o.p = 2;   //logs: "o.p changed from 1 to 2"

Sto lavorando su Javascript per gli ultimi anni e mai usato queste funzioni.
Qualcuno può gettare un po 'buoni casi di utilizzo in cui queste funzioni sarà utile?

È stato utile?

Soluzione

Cosa orologio è veramente progettato per la convalida dei valori delle proprietà. Per esempio si potrebbe convalidare che qualcosa è un numero intero:

obj.watch('count', function(id, oldval, newval) {
    var val = parseInt(newval, 10);
    if(isNaN(val)) return oldval;
    return val;
});

Si può usare per convalidare la lunghezza della stringa:

obj.watch('name', function(id, oldval, newval) {
    return newval.substr(0, 20);
});

Tuttavia, questi sono disponibili solo nelle versioni più recenti del SpiderMonkey JavaScript del motore. Gran se si utilizza Jaxer o incorporare il motore SpiderMonkey, ma non realmente disponibili nel tuo browser ancora (se non si è utilizzando FF3).

Altri suggerimenti

Object.defineProperty Object.prototype.\__defineGetter__ (o \__defineSetter__) per vedere dove questa funzionalità si sta dirigendo.

<=> dovrebbe essere disponibile in tutti i browser moderni molto presto ora.

E 'ora 2018 e le risposte a questa domanda sono un po' obsolete:

Oggi, è ora possibile utilizzare il Proxy oggetto per monitorare (e intercetta) Le modifiche apportate a un oggetto. E 'costruito appositamente per quello che il PO sta cercando di fare. Ecco un esempio di base:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

Gli unici inconvenienti della Proxy oggetto sono:

  1. Il Date oggetto non è disponibile nei browser meno recenti (come IE11) e il polyfill non può replicare completamente <=> funzionalità.
  2. Gli oggetti proxy non sempre si comportano come previsto con oggetti speciali (ad esempio, <=>) -. L'<=> oggetto è meglio in coppia con oggetti semplici o matrici

Se è necessario osservare le modifiche apportate ad un oggetto nidificato , quindi è necessario utilizzare una biblioteca specializzata come osservabile Slim (che ho creato). Funziona in questo modo:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]

Si potrebbe dare un'occhiata alla Javascript Propery Eventi biblioteca. Si tratta di una piccola biblioteca che si estende Object.defineProperty con alcuni chiamanti di eventi, che ho fatto di recente. Si aggiunge un paio di on[event] proprietà che possono essere utilizzate come le onerror proprietà di HTML-Objects. Essa ha anche un semplice controllo di tipo, che chiama l'evento <=> se non riesce.

Prendendo il codice che si tradurrebbe in qualcosa di simile a questo:

var o = {}
Object.defineProperty(o, "p", {
    value:1,
    writable:true,
    onchange:function(e){
        console.log("o." + e.target + " changed from " + e.previousValue + " to " + e.returnValue);
    }
})

È possibile utilizzare setInterval

Object.prototype.startWatch = function (onWatch) {

    var self = this;

    if (!self.watchTask) {
        self.oldValues = [];

        for (var propName in self) {
            self.oldValues[propName] = self[propName];
        }


        self.watchTask = setInterval(function () {
            for (var propName in self) {
                var propValue = self[propName];
                if (typeof (propValue) != 'function') {


                    var oldValue = self.oldValues[propName];

                    if (propValue != oldValue) {
                        self.oldValues[propName] = propValue;

                        onWatch({ obj: self, propName: propName, oldValue: oldValue, newValue: propValue });

                    }

                }
            }
        }, 1);
    }



}

var o = { a: 1, b: 2 };

o.startWatch(function (e) {
    console.log("property changed: " + e.propName);
    console.log("old value: " + e.oldValue);
    console.log("new value: " + e.newValue);
});

Object.defineProperty

Promessa

rimuovere Promessa e mantenere richiamata solo se Promessa non è supportata nel tuo browser destinazione

Importante:

1) Siate consapevoli del comportamento asincrono sull'utilizzo promessa.

2) Object.defineProperty non fa scattare la richiamata, assegnare solo operatore '=' fa

Object.onPropertySet = function onPropertySet(obj, prop, ...callback_or_once){
    let callback, once;
    for(let arg of callback_or_once){
        switch(typeof arg){
        case "function": callback = arg; break;
        case "boolean": once = arg; break;
        }
    }


    let inner_value = obj[prop];
    let p = new Promise(resolve => Object.defineProperty(obj, prop, {
        configurable: true,
        // enumerable: true,
        get(){ return inner_value; },
        set(v){
            inner_value = v;
            if(once){
                Object.defineProperty(obj, prop, {
                    configurable: true,
                    // enumerable: true,
                    value: v,
                    writable: true,
                });
            }
            (callback || resolve)(v);
        }
    }));
    if(!callback) return p;
};

// usage
let a = {};
function sayHiValue(v){ console.log(`Hi "${v}"`); return v; }

// do
Object.onPropertySet(a, "b", sayHiValue);
a.b = 2; // Hi "2"
a.b = 5; // Hi "5"

// or
Object.onPropertySet(a, "c", true).then(sayHiValue).then(v => {
    console.log(a.c); // 4 // because a.c is set immediatly after a.c = 3
    console.log(v); // 3 // very important: v != a.c if a.c is reassigned immediatly
    a.c = 2; // property "c" of object "a" is re-assignable by '=' operator
    console.log(a.c === 2); // true
});
a.c = 3; // Hi "3"
a.c = 4; // (Nothing)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top