Last active
September 11, 2015 15:15
-
-
Save papandreou/52a3df813d49de6cac19 to your computer and use it in GitHub Desktop.
Stripped down version of ko.observable with all the prototype trickery
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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