JavaScript proxy alternatives

I want to use Proxy in a custom ObservableList class that contains an Array . Since Proxy is only available after ES6, I wonder if there is an alternative implementation.

My requirement is to update (and not notice) the observers after the changes of the ObservableList are changed, so that the observers always consist of observables with some filtering or matching method.

 var activities = new ObservableList(['reading', 'swimming']); var sAct = activities.filter(function(v) { return v[0] === 's'; }); // expect sAct.list to be ['swimming'] var meAct = activities.map(function(v) { return 'I am ' + v; }); // expect meAct.list to be ['I am reading', 'I am swimming'] activities.list.push('smiling'); console.log(sAct.list, meAct.list); // expect sAct.list to be ['swimming', 'smiling'] // expect meAct.list to be ['I am reading', 'I am swimming', 'I am smiling'] activities.list[1] = 'snoopying'; console.log(sAct.list, meAct.list); // expect sAct.list to be ['swimming', 'snoopying'] // expect meAct.list to be ['I am reading', 'I am snoopying', 'I am smiling'] 

My implementation with Proxy is available at https://jsfiddle.net/ovilia/tLmbptr0/3/

+7
javascript ecmascript-6 observer-pattern es6-proxy
source share
3 answers

As described in the questions, I need an ObservableList contain an Array , and not extend it, as Jim did in his complex answer. And, surprisingly, I found that this can be easily achieved by wrapping the original Array operations .

One of the limitations is that the index operation is not responsive in my implementation, because I could not find the right way to capture index operations. If you have a better idea, feel welcome to tell me! Xd

Here's the full implementation.

 export class ObservableList { list: Array<any>; private _observer: Array<ObserverList>; constructor(list?: Array<any>) { this.list = list || []; this._initList(); this._initMethods(); this._observer = []; } notify(): void { for (let o of this._observer) { o.update(); } } private _initList(): void { var that = this; var operations = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; for (let operation of operations) { this.list[operation] = function() { var res = Array.prototype[operation].apply(that.list, arguments); that.notify(); return res; } } } private _initMethods(): void { var that = this; var methods = ['filter', 'map']; for (let method of methods) { this[method] = (formatter: Function): ObserverList => { var observer = new ObserverList(that, formatter, method); this._observer.push(observer); return observer; } } } } export class ObserverList { public list: Array<any>; constructor(public observable: ObservableList, public formatter: Function, public method: string) { this.list = []; this.update(); } update(): void { var list = []; var master = this.observable.list; for (var i = 0, len = master.length; i < len; ++i) { if (this.method === 'filter') { if (this.formatter(master[i])) { list.push(master[i]); } } else if (this.method === 'map') { list.push(this.formatter(master[i])); } else { console.error('Illegal method ' + this.method + '.'); } } this.list = list; } } 
-one
source share

used by defineProperty .

not quite what you want. I just implemented a reactive array. but I think this may work in your problems.

bad parts:

  • detect tons of getters / setters on target.
  • Access to indexes that are not defined will not respond.
  • update() optimized.

good details:

  • ES5 friendly.
  • If indexes are not needed, using set(i, val)/get(i) will be reactive.

https://jsfiddle.net/jimnox/jrtq40p7/2/

+2
source share

Is using a proxy server a tough requirement? I would not recommend a proxy for general programming tasks, as you may find yourself in unpredictable and hard-to-reach side effects.

If you store data and functions for converting it, avoid mutable ones. If possible, I think you will get simpler code that is easier to maintain.

 var activities = ['reading', 'swimming']; var sfilter = function(activities){ return activities.filter(function(v){ return v[0] === 's'; }); }; console.log(sfilter(activities)); var memap = function(activities){ return activities.map(function(v){ return 'I am ' + v; }); }; console.log(memap(activities)); activities.push('smiling'); console.log(sfilter(activities)); console.log(memap(activities)); // Yes, I know this doesn't work in quite the same way, // but you're asking for trouble here since in your // code you're appending to one list, but overwriting // an element in the other. activities[1] = 'snoopying'; console.log(sfilter(activities)); console.log(memap(activities)); 

Stick to the One Source of Truth and observe it. With each copy, you multiply the complexity of the state. This makes debugging, testing, and code expansion difficult.

0
source share

All Articles