PropertyChanges

A prototype that provides the interface for listening to and dispatching synchronous property change notifications.

ECMAScript 5 introduces property descriptors to JavaScript. The Object.defineProperty interface allows us to install get and set methods that intercept changes to particular properties. This allows us to watch for changes to specific methods on arbitrary objects.

The property change listener system installs property descriptors on arbitrary objects.

Arrays are special. You cannot add a change listener on length, and it would be impractical to install change listeners on every index of an array. The collections/listen/array-changes module provides an override for makeObservable that instead swaps out the implemntations of all array change methods and manually dispatches property changes to each observed index and the length.

However, property change listeners cannot observe the effect of the delete operator, because deletion changes the property descriptor. Setting a value to null or undefined should suffice in all cases where property change listeners are involved.

Arbitrary objects

Objects do not need to implement the property changes interface to be observable. The PropertyChanges constructor provides alternate methods to those on the prototype that accept the desired object as a first argument.

var object = {x: 10};
function xChange(value, key, object) {}
PropertyChanges.addOwnPropertyChangeListener(object, "x", xChange);

Version 2

This property changes interface is endemic to Collections version 1. In particular, property change listeners do not receive both the old and new value, so you must install separate change and will-change listeners if you want to see both values. The system will ignore duplicate requests to install a specific change listener for a key and beforeChange flag, but will throw an error if you unregister multiple times. In version 2, we will introduce property observers which overcome these limitations. Particularly, in version 2, change observers have much less book-keeping (just an array for each property and phase), allow redundant listeners, gracefully handle redundant cancellations, and recycle the change observer objects to reduce garbage collections. Change observers will also compose better, allowing one change observer to be automatically be created and cancelled depending on the value of another observer.

Methods

addOwnPropertyChangeListener(key, listener, beforeChange?)

Adds a listener for an owned property with the given name.

addBeforeOwnPropertyChangeListener(name, listener)

Adds a listener for before a property changes.

removeOwnPropertyChangeListener(name, listener, beforeChange?)

Unregisters a property change listener provided by addOwnPropertyChangeListener.

removeBeforeOwnPropertyChangeListener(key, listener)

Unregisters a property change listener provided by addBeforeOwnPropertyChangeListener or addOwnPropertyChangeListener with the beforeChange flag.

dispatchOwnPropertyChange(key, value, beforeChange?)

Informs property change listeners that the value for a property name has changed.

dispatchBeforeOwnPropertyChange(key, value)

Informs property change listeners that the value for a property name will change.

makePropertyObservable(name)

May perform internal changes necessary to dispatch property changes for a particular name.

Usage

require("collections/shim-object");
var PropertyChanges = require("collections/listen/property-changes");
Object.addEach(MyConstructor.prototype, PropertyChanges.prototype);
  • PropertyChanges
Source code