getters & setters

var o = {
  a: 7,
  get b() {
    return this.a + 1;
  },
  set c(x) {
    this.a = x / 2
  }
};

console.log(o.a); // 7
console.log(o.b); // 8
o.c = 50;
console.log(o.a); // 25
var log = ['test'];
var obj = {
  get latest () {
    if (log.length == 0) return undefined;
    return log[log.length - 1]
  }
}
console.log (obj.latest); // Will return "test".
var language = {
  set current (name) {
    this.log.push(name);
  },
  log: []
}

language.current = 'EN';
console.log(language.log); // ['EN']

language.current = 'FA';
console.log(language.log); // ['EN', 'FA']

Object.observe() (Deprecated)

var obj = {
  foo: 0,
  bar: 1
};

Object.observe(obj, function(changes) {
  console.log(changes);
});

obj.baz = 2;
// [{name: 'baz', object: <obj>, type: 'add'}]

obj.foo = 'hello';
// [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]

delete obj.baz;
// [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]

Object.defineProperty(obj, 'foo', {writable: false});
// [{name: 'foo', object: <obj>, type: 'reconfigure'}]

Object.setPrototypeOf(obj, {});
// [{name: '__proto__', object: <obj>, type: 'setPrototype', oldValue: <prototype>}]

Object.seal(obj);
// [
//   {name: 'foo', object: <obj>, type: 'reconfigure'},
//   {name: 'bar', object: <obj>, type: 'reconfigure'},
//   {object: <obj>, type: 'preventExtensions'}
// ]

MutationObserver

// select the target node
var target = document.getElementById('some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

Proxy

var handler = {
    get: function(target, name){
        return name in target?
            target[name] :
            37;
    }
};

var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

observer a nested object (unstable version)

  • setter & getter
var functionalProperty = function(obj, property, setter, getter) {
  obj._data = obj._data || {};
  obj._data[property] = obj[property];

  Object.defineProperty(obj, property, {
    enumerable: true,
    set: function(x) {
      setter && setter.call(this, property, x);
      this._data[property] = x;
    },
    get: function() {
      getter && getter.call(this, property);
      return this._data[property];
    }
  })
}

var functionalProperties = function(obj, setter, getter) {
  if (typeof obj !== 'object') return;

  for (var i in obj) {
    if (typeof obj[i] !== 'function' && i !== '_data') {
      functionalProperty(obj, i, setter, getter)

      // if (typeof obj[i] === 'object' && !(obj[i] instanceof Array)) {
      //   functionalProperties(obj[i], setter, getter)
      // }
    }
  }
}
  • proxy
var deepProxy = function(obj, setter) {
  for (var i in obj) {
    if (typeof obj[i] === 'object') {
      obj[i] = deepProxy(obj[i], setter)
    }
  }
  return new Proxy(obj, {set: setter});
}
  • proxy-2
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#Methods
// http://stackoverflow.com/questions/41299642/how-to-use-javascript-proxy-for-nested-objects
var handler = {
  get: function(target, key) {
    if (typeof target[key] === 'object' && target[key] !== null) {
      return new Proxy(target[key], handler)
    } else {
      return target[key];
    }
  },
  set: function(target, key, value) {
    console.log('set ' + key)
    target[key] = value;
    return true
 }
}

var data = new Proxy({}, handler);

data.a = 'a';
data.b = {c: 'cc'}
data.b.c = 'abc'
data.d = {
  a: 'a',
  b: 'b',
  c: {
    e: 'e'
  }
}
data.d.c.e = 'ee'

var data = new Proxy({a:'', b:''}, handler)
  • proxy-3 (polyfill)
    // https://github.com/GoogleChrome/proxy-polyfill.git
    var ele = {data: null};
    var handler = {
    get: function(target, key) {
      if (typeof target[key] === 'object' && target[key] !== null) {
        return new Proxy(target[key], handler)
      } else {
        return target[key];
      }
    },
    set: function(target, key, value) {
      console.log('set ' + key)
      target[key] = value;
      return true
     }
    }
    ele = new Proxy(ele, handler);
    ele.data = {a: 'a', b: {bb: 'bb'}}
    ele.data.a = 'aa';