Skip to content

Instantly share code, notes, and snippets.

@papandreou
Last active September 11, 2015 15:15
Show Gist options
  • Save papandreou/52a3df813d49de6cac19 to your computer and use it in GitHub Desktop.
Save papandreou/52a3df813d49de6cac19 to your computer and use it in GitHub Desktop.
Stripped down version of ko.observable with all the prototype trickery
function setPrototypeOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}
var canSetPrototype = ({ __proto__: [] } instanceof Array);
var setPrototypeOfOrExtend = canSetPrototype ? setPrototypeOf : function extend(target, source) {
if (source) {
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
return target;
};
var subscribableFn = {
init: function(instance) {
instance._subscriptions = {};
instance._versionNumber = 1;
}
};
function Subscribable() {
setPrototypeOfOrExtend(this, Subscribable.fn);
subscribableFn.init(this);
}
// For browsers that support proto assignment, we overwrite the prototype of each
// observable instance. Since observables are functions, we need Function.prototype
// to still be in the prototype chain.
if (canSetPrototype) {
setPrototypeOf(subscribableFn, Function.prototype);
}
Subscribable.fn = subscribableFn;
var shouldUseSymbol = typeof Symbol === 'function';
var latestValueSymbol = shouldUseSymbol ? Symbol('_latestValue') : '_latestValue';
function createObservable(initialValue) {
function observable() {
if (arguments.length > 0) {
// Write
observable[latestValueSymbol] = arguments[0];
return this; // Permits chained assignments
}
else {
return observable[latestValueSymbol];
}
}
observable[latestValueSymbol] = initialValue;
// Inherit from 'subscribable'
if (canSetPrototype) {
// 'subscribable' will come for free when we inherit from 'observable', so just set up the internal state needed for subscribables
Subscribable.fn.init(observable);
} else {
// 'subscribable' won't be on the prototype chain unless we put it there directly
Subscribable.call(observable);
}
// Inherit from 'observable'
setPrototypeOfOrExtend(observable, observableFn);
return observable;
}
// Define prototype for observables
var observableFn = {
peek: function() { return this[latestValueSymbol]; }
};
// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the createObservable constructor
if (canSetPrototype) {
setPrototypeOf(observableFn, Subscribable.fn);
}
var foo = createObservable();
foo(123);
console.log(foo.peek());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment