Skip to content

Instantly share code, notes, and snippets.

@madbook
Last active December 16, 2015 22:28
Show Gist options
  • Save madbook/5506730 to your computer and use it in GitHub Desktop.
Save madbook/5506730 to your computer and use it in GitHub Desktop.
Simple constructor function for creating tree-like object structures. Useful if you need simple inheritance on a tree-like data structure.
/**
* every NodeObject's prototype is another NodeObject. The lowest level
* NodeObject's prototype is the NodeObject prototype.
*
* Each NodeObject has two default properties
* {NodeObject} parent : reference to the NodeObject that created this, also
* will be this NodeObject's prototype
* {NodeObjects[]} childNodes : every node created from this node using the
* create method will be added to this array
*
* these properties are non-enumerable, so the resulting objects are safe
* to enumerate over in for loops
*/
function NodeObject (attributeList) {
var node = Object.create(this, {
parent: { value: this },
childNodes: { value: [] }
});
var key;
if (attributeList instanceof Object)
for (key in attributeList) node[key] = attributeList[key];
return node;
}
// create a child node. The node that calls this method will be the new
// node's prototype
Object.defineProperty(NodeObject.prototype, 'create', {
value: function (attributeList) {
var child = NodeObject.call(this, attributeList)
this.childNodes.push(child);
return child;
}
});
// creates a new root node. Its necessary to call the NodeObject
// constructor this way for a root-level node, so that it's prototype is
// the NodeObject prototype and not the window
NodeObject.createRoot = function (attributeList) {
return NodeObject.call(NodeObject.prototype, attributeList);
};
@madbook
Copy link
Author

madbook commented May 3, 2013

example usage, this...

nodeObj = NodeObject.createRoot({ foo: 123 });
nodeObj.create({ bar: 456 });
nodeObj.create({ baz: 'abc' });

...is roughly equivalent to...

nodeObject = {
  foo: 123,
  childNodes: [
      { 
        bar: 456,
        childNodes: [],
        parent: nodeObject
      },
      { 
        baz: 'abc'
        childNodes: [],
        parent: nodeObject
      }
    ],
    parent: NodeObject.prototype
};

...but with the added benefit of this working

console.log(nodeObj.childNodes[0].foo === 123); // true

@madbook
Copy link
Author

madbook commented May 3, 2013

Example: setting up a chain where foo inherits from bar, which inherits from bat
compare the standard way, using Object.create

var foo = { fooProp: 'this is a foo' };
var bar = Object.create(foo);
bar.barProp = 'this is a bar';
var bat = Object.create(foo);
bat.batProp = 'this is a bat';

Its not terrible (especially if you know how its done without Object.create),
but its not great either. We can't define the bar and bat objects using
object literal syntax anymore. Furthermore, we have no way of navigating the
inheritance chain (ie, from the foo object, get the bar or bat objects);

Now, see it my way

var foo = NodeObject.create({ fooProp: 'this is a foo' });
foo.create({ barProp: 'this is a bar' });
foo.create({ batProp: 'this is a bat' });

less lines, consistent definition syntax, and we can go from foo->bar and from
bar->foo using the parent/childNodes properties.

@lukebennett
Copy link

FYI you have a typo in your second example:

var bat = Object.create(bat);

Should be

var bat = Object.create(foo);

@madbook
Copy link
Author

madbook commented May 3, 2013

fixed, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment