From 57d9f3d2c9711c965c5ddf959fed91e6924dca63 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Tue, 16 Jul 2019 23:49:32 +0300 Subject: [PATCH] docs, some refactoring + renaming... Signed-off-by: Alex A. Naanou --- README.md | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++- object.js | 99 +++++++++++++++++-------------------------------- package.json | 2 +- 3 files changed, 135 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 77f527a..04ca517 100755 --- a/README.md +++ b/README.md @@ -1 +1,101 @@ -# object.js \ No newline at end of file +# object.js + +object.js provides a set of tools for constructing and maintaining object +constrictors and for managing their inheritance relations. + + +This is an elternative to the ES6 `class` syntax in JavaScript and provides +several advantages: +- simple way to define normal and class methods, properties and attributes, +- uniform and minimalistic definition syntax based on basic JavaScript + object syntax no special cases or special syntax, +- _transparantly_ based on _JavaScript's_ prototypical inheritance model, +- more granular instance construction (a-la _Python's_ `.__new__(..)` + and `.__init__(..)` methods) +- less restrictive: + - `new` is optional + - all input components are reusable + +Disadvantages compared to the `class` syntax: +- no _sytactic sugar_ +- a slightly more complicated `super` call method + + +## Usage + +```javascript +var object = require('ig-object') +``` + +Create a basic constructor... + +```javascript +// NOTE: new is optional here... +var A = new object.Constructor('A', {}) +``` + + +In _JavaScript_ constructor `B` inherits from constructor `A` iff +`B.prototypes` is _prototype_ of `A.prototype`. So to implement inheritance +we simply need to _link_ the prototypes of two constructors via `.__proto__`, +`Object.create(..)` or other means. + +```javascript +// NOTE: we could simply use A() or new A() here but that would call +// the active constructors if they are defined which might not be +// desirable at definition time... +var B = object.Constructor('B', {__proto__: A.prototype}) +var C = object.Constructor('C', Object.create(B.prototype)) +``` + +```javascript +var c = C() // or new C() + +c instanceof C // -> true +c instanceof B // -> true +c instanceof A // -> true +``` + +```javascript +var Base = object.makeConstructor() +``` + + +## Components + +``` +parent(, ) +parent(, , ) + -> +``` + +``` +mixin(, , ...) + -> +``` + +``` +mixinFlat(, , ...) + -> +``` + +``` +makeConstructor(, ) +makeConstructor(, , ) + -> + +makeConstructor(, ) +makeConstructor(, , ) + -> +``` + + + +## License + +[BSD 3-Clause License](./LICENSE) + +Copyright (c) 2019, Alex A. Naanou, +All rights reserved. + + \ No newline at end of file diff --git a/object.js b/object.js index 7274c32..61fede1 100755 --- a/object.js +++ b/object.js @@ -31,8 +31,7 @@ function(text){ return lines .map(function(line, i){ return i == 0 ? line : line.slice(l) }) - .join('\n') -} + .join('\n') } @@ -63,8 +62,7 @@ function(method, name, that){ that = that.__proto__ } // return the next method... - return that.__proto__[name] -} + return that.__proto__[name] } @@ -118,17 +116,12 @@ function(root, ...objects){ // // // Make a constructor with an object prototype... -// makeConstructor(, ) -// -> constructor -// -// Make a constructor with an init function prototype... -// makeConstructor(, ) +// Constructor(, ) // -> constructor // // Make a constructor with a prototype (object/function) and a class // prototype... -// makeConstructor(, , ) -// makeConstructor(, , ) +// Constructor(, , ) // -> constructor // NOTE: the defines a set of class methods and // attributes. @@ -172,16 +165,23 @@ function(root, ...objects){ // Inheritance: // A simple way to build C -> B -> A chain would be: // -// var A = makeConstructor('A', {}) +// // NOTE: new is optional... +// var A = new Constructor('A', {}) // // // NOTE: the prototype is an instance and not a constructor, // // this is obvious if one considers that in JS there are // // no classes and inheritance is done via object prototypes // // but this might be a gotcha to people coming from the // // class-object world. -// var B = makeConstructor('B', A()) +// // NOTE: we are creating instances here to provide isolation +// // between A and B prototypes... +// // two other ways to do this would be: +// // Object.create(A.prototype) +// // or: +// // {__proto__: A.prototype} +// var B = Constructor('B', A()) // -// var C = makeConstructor('C', B()) +// var C = Constructor('C', {__proto__: B.prototype}) // // var c = C() // @@ -219,34 +219,15 @@ function(root, ...objects){ // ...mainly for inheritance. // ...would also be helpful in this case to call all the // constructors in the chain -var makeConstructor = -module.makeConstructor = -function makeConstructor(name, a, b){ +var Constructor = +module.Constructor = +// shorthand... +module.C = +function Constructor(name, a, b){ var proto = b == null ? a : b var cls_proto = b == null ? b : a var _constructor = function Constructor(){ - /* - // XXX BUG: if the constructor is called from it's instance this will - // return the instance and not a new object... - // in case this is called as a function (without new)... - if(this.constructor !== _constructor){ - // NOTE: the following does the job of the 'new' operator but - // with one advantage, we can now pass arbitrary args - // in... - // This is equivalent to: - // return new _constructor(json) - var obj = {} - obj.__proto__ = _constructor.prototype - // XXX for some reason this does not resolve from .__proto__ - obj.constructor = _constructor - //obj.__proto__.constructor = _constructor - - } else { - var obj = this - } - */ - // NOTE: the following does the job of the 'new' operator but // with one advantage, we can now pass arbitrary args // in... @@ -255,51 +236,32 @@ function makeConstructor(name, a, b){ var obj = _constructor.prototype.__new__ instanceof Function ? _constructor.prototype.__new__({}, ...arguments) : {} + obj.__proto__ = _constructor.prototype - // XXX for some reason this does not resolve from .__proto__ - // XXX this also is a regular attr and not a prop... - //obj.constructor = _constructor Object.defineProperty(obj, 'constructor', { value: _constructor, enumerable: false, }) - //obj.__proto__.constructor = _constructor - - // explicit init... - if(proto instanceof Function){ - proto.apply(obj, arguments) - } // load initial state... - if(obj.__init__ instanceof Function){ - obj.__init__.apply(obj, arguments) - } + obj.__init__ instanceof Function + && obj.__init__(...arguments) return obj } - /* XXX for some reason this works for the _constructor but all - * instances get the wrong name resolved... - Object.defineProperty(_constructor, 'name', { - value: name, - }) - */ - // just in case the browser refuses to change the name, we'll make it // a different offer ;) - if(_constructor.name == 'Constructor'){ - // skip for chrome app... - //&& !(window.chrome && chrome.runtime && chrome.runtime.id)){ - eval('_constructor = '+ _constructor + _constructor.name == 'Constructor' + && eval('_constructor = '+ _constructor .toString() .replace(/Constructor/g, name)) - } // set an informative .toString... // NOTE: do this only if .toString(..) is not defined by user... - if((cls_proto || {}).toString() == ({}).toString()){ + ;((cls_proto || {}).toString() == ({}).toString()) // XXX is this the right way to go or should we set this openly??? - Object.defineProperty(_constructor, 'toString', { + && Object.defineProperty(_constructor, 'toString', { value: function(){ var args = proto.__init__ ? proto.__init__ @@ -316,11 +278,13 @@ function makeConstructor(name, a, b){ }, enumerable: false, }) - } _constructor.__proto__ = cls_proto _constructor.prototype = proto - _constructor.prototype.constructor = _constructor + Object.defineProperty(_constructor.prototype, 'constructor', { + value: _constructor, + enumerable: false, + }) return _constructor } @@ -328,5 +292,8 @@ function makeConstructor(name, a, b){ + + + /********************************************************************** * vim:set ts=4 sw=4 : */ return module }) diff --git a/package.json b/package.json index 71cbe5f..a01fd4b 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-object", - "version": "1.5.0", + "version": "2.0.0", "description": "", "main": "object.js", "scripts": {