Skip to content

Instantly share code, notes, and snippets.

@distransient
Last active February 19, 2016 20:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save distransient/a3b039c9ae93bd05d524 to your computer and use it in GitHub Desktop.
Save distransient/a3b039c9ae93bd05d524 to your computer and use it in GitHub Desktop.
Javascript prototype demonstration
// since we know how prototype works, now we can forget it exists
// and forfeit from using it in our code, because of the penalty
// it incurs in the form of extra complexity
function numberArray() {
var x = { value: Array.apply(null, arguments) }
x.sum = function () { return this.value.reduce(function(x, y) { return x + y }) }
return x
}
// We may not be able to index numberArray directly (we have
// to access numberArray.value), but its implementation and
// likelihood of breaking in non-obvious ways is much smaller.
console.log(numberArray(2, 3, 9, 1).sum()) // => 15
// This will list the properties "value" and "sum",
// but we can do better, since we don't want methods
// on our data structure to be enumerable.
for(var x in numberArray(1, 8, 2))
console.log(x)
function improvedNumberArray() {
// This creates the object with a non-configurable,
// enumerable, or writable field named "sum" with
// the value of the function.
var x = Object.create(null, { sum: { value:
function () { return this.value.reduce(
function(x, y) { return x + y }) } } })
x.value = Array.apply(null, arguments)
return x
}
console.log(improvedNumberArray(2, 3, 9, 1).sum()) // => 15
for(var x in improvedNumberArray(1, 8, 2))
console.log(x) // => "value"; Sum isn't enumerated!
// Prototype inheritance
function ArrayWithValue(firstValue) {
var x = Array.isArray(this) ? this : []
// Apply inheritance of methods to value
// Note: changing the prototype of an object whether via
// __proto__ or Object.setPrototypeOf, is going to be slow.
// This is only unavoidable in the case of how weird Arrays
// are in JS. If you're working with a non-array superclass,
// use Object.create() instead.
// To learn more about the weirdness of ECMAScript Arrays,
// read this: http://goo.gl/Mw5Ows
if (!x instanceof ArrayWithValue)
Object.setPrototypeOf(x, ArrayWithValue.prototype)
x.push(firstValue)
return x
}
// Inherit methods from array
ArrayWithValue.prototype = new Array;
// => ['hello, world!']
console.log(new ArrayWithValue('hello, world!'))
// Subclass implementation
function TwoValues(firstValue, secondValue) {
// TODO: experiment more with subclasses of Array subclasses
var x = ArrayWithValue.call(Object.setPrototypeOf(
[], TwoValues.prototype), firstValue)
x.push(secondValue)
return x
}
// This is why we use "new SuperClass" instead of "SuperClass"
// We can modify the prototype and add methods to the subclass
// through the prototype now, without mutating the superclass
TwoValues.prototype = new ArrayWithValue
TwoValues.prototype.sum = function () {
return this.reduce(function(x, y) { return x + y }) }
console.log((new TwoValues(3,4)).sum()) // => 7
// Prototype extension
// don't do this on globals! it's just for demonstration.
// modifying global prototypes will change how
// instances of that class behave for *everyone*
Object.prototype.add = function(x) { return this + x }
console.log('foo'.add('bar')) // => 'foobar'
console.log((1).add(1)) // => 2
// (simplified) Javascript implementation of "new" operator
// This isn't meant to be used, but is more of a tool to
// understand how "new" works.
function neu(x, args) {
// Makes an object using specified prototype
// I should eventually write a little implementation
// of this as well, for clarity on the prototype chain.
var instance = Object.create(x.prototype || null)
// Applies constructor to object, returns instance either
// returned from constructor, or modified by constructor.
return x.apply(instance, args) || instance
}
// To demonstrate...
function SimpleClass(width, height) {
this.width = width
this.height = height
}
SimpleClass.prototype.area = function () {
return this.width * this.height }
console.log((new SimpleClass(2,3)).area()) // => 6
console.log((neu(SimpleClass, [2,3])).area()) // also => 6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment