ObservableList

by jimnox

JavaScript

function ObservableList(arr) {
  var buffer = arr ? arr.slice(0) : []
  Object.defineProperties(this, {
    buffer: {
      enumerable: false,
      writable: false,
      value: buffer
    },
    index: {
      enumerable: false,
      writable: true,
      value: 0
    },
    observers: {
      enumerable: false,
      writable: false,
      value: []
    }
  })
  this.updateIndexers()
}
ObservableList.defineReactiveGetterSetter = function(target, key, enumerable) {
  Object.defineProperty(target, String(key), {
    enumerable: enumerable,
    configurable: true,
    get: function() {
      return this.buffer[key]
    },
    set: function(val) {
      this.buffer[key] = val
      this.updateIndexers()
      this.update()
      return val
    }
  })
}
ObservableList.createMutator = function(name, returnFn) {
  return function() {
    var result = this.buffer[name].apply(this.buffer, arguments)
    this.updateIndexers()
    this.update()
    return result
  }
}
ObservableList.createIterator = function(name) {
  return function() {
    var args = arguments
    var me = this
    var ob = {
      buffer: [],
      update: function() {
        ob.buffer.length = 0
        // to be optimized LoL
        var result = me.buffer[name].apply(me.buffer, args)
        ob.buffer.push.apply(ob.buffer, result)
      }
    }
    ob.update()
    this.observers.push(ob)
    return ob.buffer
  }
}
var ObservableListPrototype = {
  updateIndexers: function() {
    var len = this.buffer.length
    var index = this.index
    while (index > len) {
      delete this[index]
      index--
    }
    // to support `arr[arr.length] = xxx`
    // better than nothing -_-"
    while (index >= 0 && index <= len) {
      ObservableList.defineReactiveGetterSetter(this, index, true)
      index++
    }
    this.index = index
  },
  toArray: function() {
    return this.buffer.slice(0)
  },
  update: function() {
    for (var i = 0, len = this.observers.length; i < len; ++i) {
     ...