Skip to content

Instantly share code, notes, and snippets.

@Gozala
Created June 13, 2011 14:58
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 Gozala/7e649e8c33d412e90178 to your computer and use it in GitHub Desktop.
Save Gozala/7e649e8c33d412e90178 to your computer and use it in GitHub Desktop.
Alternative sugar for classes in ES.next
var _target = '[[target]]';
var _name = '[[name]]';
var _this = '[[this]]';
Function.prototype.extend = function extend(properties) {
var prototype = Object.create(this.prototype);
Object.getOwnPropertyNames(properties).forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(properties, name);
var wrappedDesc = wrapDescriptor(desc, name, prototype);
Object.defineProperty(prototype, name, wrappedDesc);
});
var constructor = prototype.constructor;
constructor.__proto__ = this;
constructor.prototype = prototype;
return constructor;
}
function wrapDescriptor(descriptor, name, prototype) {
var wrapped = {};
if ('writable' in descriptor)
wrapped.writable = descriptor.writable;
if ('enumerable' in descriptor)
wrapped.enumerable = descriptor.enumerable;
if ('configurable' in descriptor)
wrapped.configurable = descriptor.configurable;
if ('value' in descriptor) {
wrapped.value = typeof descriptor.value !== 'function' ? descriptor.value :
wrap(descriptor.value, name, prototype)
}
if ('get' in descriptor)
wrapped.get = wrap(descriptor.get, name, prototype)
if ('set' in descriptor)
wrapped.set = wrap(descriptor.set, name, prototype)
return wrapped;
}
function wrap(unwrapped, name, prototype) {
var source = unwrapped.toString();
// We use `eval` just to preserve `.length` and `.name` of unwrapped function.
return eval('(' + source.substr(0, source.indexOf('{')) + '{' +
' unwrapped[_this] = this; ' +
' unwrapped[_target] = prototype; ' +
' unwrapped[_name] = name; ' +
' var value = unwrapped.apply(this, arguments); ' +
' delete unwrapped[_this]; ' +
' delete unwrapped[_target]; ' +
' delete unwrapped[_name]; ' +
' return value; ' +
' })');
}
function base() {
// constructor that called method (Super.caller is a function that actual
// constructor delegates to so we need to get it's caller to get to an actual
// constructor.
var caller = base.caller;
var target = caller[_target];
var name = caller[_name];
var self = caller[_this]
console.log(Caller = caller);
// We assume that `this` pseudo-variable is either passed via `call`, `apply`
// either it is passed implicitly in such case it matches value of `this`
// pseudo variables the `constructor`.
return Object.getPrototypeOf(target)[name].apply(self, arguments);
}
var Point = Object.extend({
constructor: function Point(options) {
this.x = options.x;
this.y = options.y;
},
serialize: function() {
return this.x + ':' + this.y;
}
});
Point.new = function() {
var instance = Object.create(this.prototype);
this.apply(instance, arguments);
return instance;
}
var p1 = new Point({ x: 10, y: 15 });
p1.serialize() // "10:15"
var p2 = Point.new({ x: 2, y: 4 });
p2.serialize() // "2:4"
var Pixel = Point.extend({
constructor: function Pixel(options) {
base(options)
this.color = options.color
},
serialize: function () {
return this.color + '@' + base()
}
});
var px1 = new Pixel({ x: 0, y: 10, color: '#fff' });
px1.serialize(); // "#fff@0:10"
var px2 = Pixel.new({ x: 17, y: 19, color: 'red' });
px2.serialize(); // red@17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment