Skip to content

Instantly share code, notes, and snippets.

@teramako
Created May 14, 2011 18:02
Show Gist options
  • Save teramako/972456 to your computer and use it in GitHub Desktop.
Save teramako/972456 to your computer and use it in GitHub Desktop.
JavaScript でクラスもどきを作る
// ===================================
// Example
// ===================================
/**
* Point
* @class
* @augments Class
* @param {Number} x x-axis
* @param {Number} y y-axis
*/
const Point = Class("Point", /** @lends Point# */ {
/** @constructs */
init: function Point (x, y) {
if (x) this.x = x;
if (y) this.y = y;
},
/**
* x-axis
* @type Number
*/
x: 0,
/**
* y-axis
* @type Number
*/
y: 0,
});
/**
* Rectangle
* @class
* @augments Point
* @param {Number} x
* @param {Number} y
* @param {Number} width
* @param {Number} height
*/
const Rectangle = Class("Rect", Point, /** @lends Rectangle# */ {
/** @constructs */
init: function Rectangle (x, y, width, height) {
if (width) this.width = width;
if (height) this.height = height;
arguments.callee.super.call(this, x, y);
},
getDimension: function Rect_getDimension () {
return this.width * this.height;
},
/**
* width of the rect
* @type Number
*/
width: 0,
/**
* height of the rect
* @type Number
*/
height: 0,
});
/**
* Square
* @class
* @augments Rectangle
* @param {Number} x
* @param {Number} y
* @param {Number} length
*/
const Square = Class("Square", Rectangle, /** @lends Square */ {
/** @constructs */
init: function Square (x, y, length) {
arguments.callee.super.call(this, x, y, length, length);
},
/**
* @name Square#length
* @type Number
*/
get length () {
return this.width;
},
set length (val) {
return this.width = this.height = val;
}
});
var p = new Point(10,10); // Point instance;
p instanceof Point; // true
p instanceof Class // true
var rect = Rectangle(10, 15, 20, 30); // can omit `new' operator
rect instanceof Rect; // true
rect instanceof Point; // true
rect instanceof Class; // true
rect.x; // 10
rect.y; // 15
rect.width; // 20
rect.height; // 30
var sq = Square(20, 10, 30);
sq.getDimension(); // 900 (30 * 30),
// vim: sw=2 ts=2 et:
/**
* @fileoverview Create Function like Class
* @author teramako teramako.at.gmail.com
* @version 0.1
* @license MIT
* @requires ECMASCript 5th and object.__proto__ property
*/
/**
* Create Function constructor
* @constructor
* @augments Object
* @param {String} [name] class name
* @param {Function} [base] base class
* @param {Object} proto
* @return {Function}
*/
function Class (name, base, proto) {
var args = Array.prototype.slice.call(arguments);
if (typeof args[0] == "string")
var name = args.shift();
var superClass = Class;
if (typeof args[0] == "function")
superClass = args.shift();
proto = args[0];
if (!name)
name = proto.__CLASS_NAME__ || superClass.__CLASS_NAME__ || "Anonymous";
proto.__proto__ = superClass.prototype;
Class.setSuper(proto, superClass.prototype);
Object.defineProperty(proto, "__CLASS_NAME__", { value: name });
var constructor = function () {
var o = Object.create(proto, { constructor: { value: constructor }});
var res = o.init.apply(o, arguments);
return res != undefined ? res : o;
};
constructor.prototype = proto;
var bound = constructor.bind(null);
bound.prototype = proto;
bound.__proto__ = Class;
return bound;
}
Object.defineProperties(Class, {
/**
* Show the first class name.
* @name Class.toString
* @function
* @return {String}
*/
toString: {
value: function () { return "[class " + this.prototype.__CLASS_NAME__ + "]"; },
},
/**
* set "super" property is references the same name property in super
* to functions and gettter/setter properties in proto
* @name Class.setSuper
* @function
* @constant
* @param {Object} proto
* @param {Object} super
*/
setSuper: {
value: function (proto, super) {
var keys = Object.getOwnPropertyNames(proto);
out:
for (var i = 0, len = keys.length; i < len; ++i) {
var key = keys[i];
if (!(key in super))
continue;
var desc = Object.getOwnPropertyDescriptor(proto, key);
if ("get" in desc) {
var p = super;
while (p !== null) {
if (Object.prototype.hasOwnProperty(p, key)) {
Object.defineProperty(proto[key], "super", desc);
continue out;
}
p = Object.getPrototypeOf(p);
}
} else if (typeof proto[key] == "function") {
Object.defineProperty(proto[key], "super", { value: super[key] });
}
}
},
},
/**
* marge properties of the second or later arguments
* to the first arguments
* @function
* @name Class.update
*/
update: {
value: function () {
var args = Array.prototype.slice.call(arguments);
var base = args.shift();
for (var i = 0; i < args.length; ++i) {
var o = args[i];
var keys = Object.getOwnPropertyNames(o);
for (var k = 0, len = keys.length; k < len; ++k) {
var key = keys[i];
Object.defineProperty(base, key, Object.getOwnPropertyDescriptor(o, key));
}
}
},
},
});
Class.prototype = Object.create({}, {
/**
* @memberof Class.prototype
* @type {String}
* @private
*/
__CLASS_NAME__: { value: "Class", },
/**
* do nothing
* @methodof Class.prototype
* @constructs
*/
init: {
value: function Class_init () {},
},
/**
* Show the first class name of the instance.
* @methodof Class.prototype
* @return {String}
*/
toString: {
value: function Class_toString () { return "[instance " + this.__CLASS_NAME__ + "]"; },
},
});
// vim: sw=2 ts=2 et:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment