Skip to content

Instantly share code, notes, and snippets.

@baluubas
Last active January 3, 2016 16:49
Show Gist options
  • Save baluubas/8492015 to your computer and use it in GitHub Desktop.
Save baluubas/8492015 to your computer and use it in GitHub Desktop.
Javascript 'classes' with private, protected and public variables and functions. Properties can be inherited. Note that this is just a theoretical excerise, I'm not using this in production.
define(['Name'], function(Name) {
var knownNamespaces = {};
function createMember(member, namespace, prototype, access) {
var name = new Name();
namespace[member] = name;
Object.defineProperty(prototype, name, {
writable: true ,
value: access[member] });
}
return {
namespace: function() { return {}; },
define: function create(namespace, declarations) {
var privateNamespace = {}
protectedNamespace = {};
if(declarations.extends) {
var inheritedNamespace = knownNamespaces[declarations.extends.__namespaceId];
_.extend(namespace, inheritedNamespace);
declarations.ctor.prototype = Object.create(declarations.extends.prototype);
}
for(var member in declarations.private) {
createMember(
member,
privateNamespace,
declarations.ctor.prototype,
declarations.private);
}
for(var member in declarations.protected) {
createMember(
member,
protectedNamespace,
declarations.ctor.prototype,
declarations.protected);
}
_.extend(namespace, privateNamespace, protectedNamespace);
for(var e in declarations.public) {
declarations.ctor.prototype[e] = declarations.public[e];
namespace[e] = e;
}
declarations.ctor.__namespaceId = new Name();
knownNamespaces[declarations.ctor.__namespaceId] = protectedNamespace;
return declarations.ctor;
}
};
});
define([], function() {
var used = {};
function Name(Owner) {
var length, str;
do {
length = 5 + Math.floor(Math.random() * 10);
str = "_";
while (length--) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
}
while (used[str]);
used[str] = true;
return new String(str); // Since this is called via `new`, we have to return an object to override the default
}
return Name;
});
define(['ClassFactory', 'View'], function(ClassFactory, View) {
var ns = ClassFactory.namespace();
return ClassFactory.define(ns, {
extends: View,
ctor: function TemplateView(options) {
View.apply(this, arguments);
},
private:{
subViews: []
},
public: {
addSubview: function(selector, view) {
this[ns.subViews].push({ selector: selector, view: view });
},
render: function() {
View.prototype.render.call(this);
var that = this;
_.each(this[ns.subViews], function(subView) {
var subViewEl = that.el.querySelector(subView.selector);
subView.view.render();
subViewEl.innerHTML = '';
subViewEl.appendChild(subView.view.el);
});
}
}
});
});
define(['ClassFactory'], function(ClassFactory) {
var ns = ClassFactory.namespace();
var View = ClassFactory.define(ns, {
ctor: function View(options) {
if(!options.template) {
throw new Error('No template specified.');
}
this[ns.template] = options.template;
this[ns.elementTag] = options.elementTag || this[ns.elementTag];
this[ns.el] = document.createElement(this[ns.elementTag]);
},
private: {
toHtml: function(data) {
return _.template(this[ns.template])(data);
}
},
protected: {
template: null,
elementTag: 'div',
serialize: function() {
return {};
}
},
public: {
el: null,
render: function() {
var data = this[ns.serialize]();
this[ns.el].innerHTML = this[ns.toHtml](data);
}
}
});
return View;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment