How to observe value changes in JS variables

2020-02-13 03:41发布

Im wondering if someone might be able to help me with something that i think it fairly straight forward:

Essentially i want to extend the prototypes of all datatypes (including intrinsic types), to allow some kind of custom functions, consider:

var x = "some string";
var y = 101;

x = "some other value";
y++;

x.onChange();
y.onChange();

This is the basic idea im after, but really what i want is to actually have the onChange (in this example) to be different so a new function for the actual variable (rather than a stardard prototype extension), ie:

x.onChange = function() {
    alert("x.onChange");
}

y.onChange = function() {
    alert("y.onChange");
}

This doesnt seem to work but i must be missing something quite simple no? I mean surely i can extend all object and types and add on new functions... no?

Any help would be greatly appreciated!

3条回答
聊天终结者
2楼-- · 2020-02-13 04:03

I might be tempted to approach this not by trying to add methods to existing types, but to create an object that can wrap a primative type. I would call this "observing" a value, and might implement it something like this:

function observable(v){
    this.value = v;

    this.valueChangedCallback = null;

    this.setValue = function(v){
        if(this.value != v){
            this.value = v;
            this.raiseChangedEvent(v);
        }
    };

    this.getValue = function(){
        return this.value;
    };

    this.onChange = function(callback){
        this.valueChangedCallback = callback;
    };

    this.raiseChangedEvent = function(v){
        if(this.valueChangedCallback){
             this.valueChangedCallback(v);
        }   
    };
}

This can then be used to observe changes in any value (so long as that value is then changed only by methods on the observable class - a small detraction IMO).

Something like this would work with the above code:

var obs = new observable(123);
obs.onChange(function(v){
         alert("value changed to: " + v);
     });

// the onChange callback would be called after something like obs.setValue(456);

Live example here --> http://jsfiddle.net/MeAhz/

查看更多
Lonely孤独者°
3楼-- · 2020-02-13 04:12

Extend the object prototype:

Object.prototype.foo = function() { alert('hello world'); };
var a = 1;
a.foo();
查看更多
在下西门庆
4楼-- · 2020-02-13 04:18

The standard DEPRECATED way : Object.observe()

The Object.observe() method was used for asynchronously observing the changes to an object. It provided a stream of changes in the order in which they occur. However, this API has been deprecated and removed from browsers.

let myObservdObject = Object.observe( { a : 'foo' }, e=>console.log('change!', e) );
myObservdObject.a = 'bee';
// callback gets executed
// and prints 'changed! in console, with the change event data

But proxies arrived to the Standard (ES6) an Object.Observe became deprecated and, in consecuence, unsupported by the browsers.

Proxies are the new way to observe... but implement a generic observer requires a more complex implementation, in comparsion with the way Object.observe used to provide us.


Observe value changes with third party libraries

You can find arround many implementations based in proxies. Some of them implement the Observer pattern, wich forces you to set or get the values using specific methods :

Observe : https://www.npmjs.com/package/observe

// define your object
var object = {a:'bee'};
// generate an observer
var observer = observe(object);
// declare the onchange event handler
observer.on( 'change', change=> console.log(change) );
// ready!
// set the value of 'a' and see how the callback is executed...
observer.set('a', 'foo')   
// get the new value
observer.get('a')   // returns 'foo'

Other libraries instead, let you interact with your variables using a more natural way:

WatchJS : https://github.com/melanke/Watch.JS/

// define your object
var object = {a:'bee'};
// generate an observer and declare de hadler
watch(object , "a" , e=>console.log(e) );
// ready!
// set the value of 'a' and see how the callback is executed...
object.a = 'foo';   
// get the new value
object.a  // returns 'foo'

My own apprach : deep-observer

All the implementaions have their own caveats, and none of them was working for my purposes, so i had to implement my own approach.

The result is a highly customizable Observer method with a really small footprint ( <100 bytes gziped)

Deep-observer : https://www.npmjs.com/package/deep-observer

// create an observable object
const myObserved = new Observer( { a : 'bee' } , e=>console.log(e) ),
// perform a modification
myObserved.a = 'foo'; 
// console  : { action:'update', oldValue:'bee', object:{a:'foo'}, name:'a' }
myObserved.a;  // returns 'foo'
查看更多
登录 后发表回答