mirror of
				https://github.com/flynx/object.js.git
				synced 2025-10-31 03:20:09 +00:00 
			
		
		
		
	docs, some refactoring + renaming...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									07d7a920fb
								
							
						
					
					
						commit
						57d9f3d2c9
					
				
							
								
								
									
										100
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								README.md
									
									
									
									
									
								
							| @ -1 +1,101 @@ | |||||||
| # object.js | # 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(<method>, <this>) | ||||||
|  | parent(<method>, <name>, <this>) | ||||||
|  |     -> <parent-method> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | mixin(<root>, <object>, ...) | ||||||
|  |     -> <object> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | mixinFlat(<root>, <object>, ...) | ||||||
|  |     -> <object> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | makeConstructor(<name>, <prototype>) | ||||||
|  | makeConstructor(<name>, <class-prototype>, <prototype>) | ||||||
|  |     -> <constructor> | ||||||
|  | 
 | ||||||
|  | makeConstructor(<name>, <init-function>) | ||||||
|  | makeConstructor(<name>, <class-prototype>, <init-function>) | ||||||
|  |     -> <constructor> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## License | ||||||
|  | 
 | ||||||
|  | [BSD 3-Clause License](./LICENSE) | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2019, Alex A. Naanou, | ||||||
|  | All rights reserved. | ||||||
|  | 
 | ||||||
|  | <!-- vim:set ts=4 sw=4 spell : --> | ||||||
							
								
								
									
										99
									
								
								object.js
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								object.js
									
									
									
									
									
								
							| @ -31,8 +31,7 @@ function(text){ | |||||||
| 	return lines | 	return lines | ||||||
| 		.map(function(line, i){  | 		.map(function(line, i){  | ||||||
| 			return i == 0 ? line : line.slice(l) }) | 			return i == 0 ? line : line.slice(l) }) | ||||||
| 		.join('\n') | 		.join('\n') } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -63,8 +62,7 @@ function(method, name, that){ | |||||||
| 		that = that.__proto__ | 		that = that.__proto__ | ||||||
| 	} | 	} | ||||||
| 	// return the next method...
 | 	// 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...
 | // 	Make a constructor with an object prototype...
 | ||||||
| // 		makeConstructor(<name>, <proto>)
 | // 		Constructor(<name>, <proto>)
 | ||||||
| // 			-> constructor
 |  | ||||||
| //
 |  | ||||||
| // 	Make a constructor with an init function prototype...
 |  | ||||||
| // 		makeConstructor(<name>, <init-func>)
 |  | ||||||
| // 			-> constructor
 | // 			-> constructor
 | ||||||
| //
 | //
 | ||||||
| // 	Make a constructor with a prototype (object/function) and a class
 | // 	Make a constructor with a prototype (object/function) and a class
 | ||||||
| // 	prototype...
 | // 	prototype...
 | ||||||
| // 		makeConstructor(<name>, <proto>, <class-proto>)
 | // 		Constructor(<name>, <class-proto>, <proto>)
 | ||||||
| // 		makeConstructor(<name>, <init-func>, <class-proto>)
 |  | ||||||
| // 			-> constructor
 | // 			-> constructor
 | ||||||
| // 			NOTE: the <class-proto> defines a set of class methods and 
 | // 			NOTE: the <class-proto> defines a set of class methods and 
 | ||||||
| // 					attributes.
 | // 					attributes.
 | ||||||
| @ -172,16 +165,23 @@ function(root, ...objects){ | |||||||
| // Inheritance:
 | // Inheritance:
 | ||||||
| // 	A simple way to build C -> B -> A chain would be:
 | // 	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,
 | // 		// NOTE: the prototype is an instance and not a constructor,
 | ||||||
| // 		//		this is obvious if one considers that in JS there are
 | // 		//		this is obvious if one considers that in JS there are
 | ||||||
| // 		//		no classes and inheritance is done via object prototypes
 | // 		//		no classes and inheritance is done via object prototypes
 | ||||||
| // 		//		but this might be a gotcha to people coming from the 
 | // 		//		but this might be a gotcha to people coming from the 
 | ||||||
| // 		//		class-object world.
 | // 		//		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()
 | // 		var c = C()
 | ||||||
| //
 | //
 | ||||||
| @ -219,34 +219,15 @@ function(root, ...objects){ | |||||||
| // 		...mainly for inheritance.
 | // 		...mainly for inheritance.
 | ||||||
| // 		...would also be helpful in this case to call all the 
 | // 		...would also be helpful in this case to call all the 
 | ||||||
| // 		constructors in the chain
 | // 		constructors in the chain
 | ||||||
| var makeConstructor = | var Constructor =  | ||||||
| module.makeConstructor = | module.Constructor = | ||||||
| function makeConstructor(name, a, b){ | // shorthand...
 | ||||||
|  | module.C = | ||||||
|  | function Constructor(name, a, b){ | ||||||
| 	var proto = b == null ? a : b | 	var proto = b == null ? a : b | ||||||
| 	var cls_proto = b == null ? b : a | 	var cls_proto = b == null ? b : a | ||||||
| 
 | 
 | ||||||
| 	var _constructor = function Constructor(){ | 	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
 | 		// NOTE: the following does the job of the 'new' operator but
 | ||||||
| 		// 		with one advantage, we can now pass arbitrary args 
 | 		// 		with one advantage, we can now pass arbitrary args 
 | ||||||
| 		// 		in...
 | 		// 		in...
 | ||||||
| @ -255,51 +236,32 @@ function makeConstructor(name, a, b){ | |||||||
| 		var obj = _constructor.prototype.__new__ instanceof Function ? | 		var obj = _constructor.prototype.__new__ instanceof Function ? | ||||||
| 			_constructor.prototype.__new__({}, ...arguments) | 			_constructor.prototype.__new__({}, ...arguments) | ||||||
| 			: {} | 			: {} | ||||||
|  | 
 | ||||||
| 		obj.__proto__ = _constructor.prototype | 		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', { | 		Object.defineProperty(obj, 'constructor', { | ||||||
| 			value: _constructor, | 			value: _constructor, | ||||||
| 			enumerable: false, | 			enumerable: false, | ||||||
| 		}) | 		}) | ||||||
| 		//obj.__proto__.constructor = _constructor
 |  | ||||||
| 
 |  | ||||||
| 		// explicit init...
 |  | ||||||
| 		if(proto instanceof Function){ |  | ||||||
| 			proto.apply(obj, arguments) |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// load initial state...
 | 		// load initial state...
 | ||||||
| 		if(obj.__init__ instanceof Function){ | 		obj.__init__ instanceof Function | ||||||
| 			obj.__init__.apply(obj, arguments) | 			&& obj.__init__(...arguments) | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		return obj | 		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
 | 	// just in case the browser refuses to change the name, we'll make it
 | ||||||
| 	// a different offer ;)
 | 	// a different offer ;)
 | ||||||
| 	if(_constructor.name == 'Constructor'){ | 	_constructor.name == 'Constructor' | ||||||
| 			// skip for chrome app...
 | 		&& eval('_constructor = '+ _constructor | ||||||
| 			//&& !(window.chrome && chrome.runtime && chrome.runtime.id)){
 |  | ||||||
| 		eval('_constructor = '+ _constructor |  | ||||||
| 				.toString() | 				.toString() | ||||||
| 				.replace(/Constructor/g, name)) | 				.replace(/Constructor/g, name)) | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	// set an informative .toString...
 | 	// set an informative .toString...
 | ||||||
| 	// NOTE: do this only if .toString(..) is not defined by user...
 | 	// 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???
 | 		// XXX is this the right way to go or should we set this openly???
 | ||||||
| 		Object.defineProperty(_constructor, 'toString', { | 		&& Object.defineProperty(_constructor, 'toString', { | ||||||
| 			value: function(){  | 			value: function(){  | ||||||
| 				var args = proto.__init__ ? | 				var args = proto.__init__ ? | ||||||
| 					proto.__init__ | 					proto.__init__ | ||||||
| @ -316,11 +278,13 @@ function makeConstructor(name, a, b){ | |||||||
| 			}, | 			}, | ||||||
| 			enumerable: false, | 			enumerable: false, | ||||||
| 		}) | 		}) | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	_constructor.__proto__ = cls_proto | 	_constructor.__proto__ = cls_proto | ||||||
| 	_constructor.prototype = proto | 	_constructor.prototype = proto | ||||||
| 	_constructor.prototype.constructor = _constructor | 	Object.defineProperty(_constructor.prototype, 'constructor', { | ||||||
|  | 		value: _constructor, | ||||||
|  | 		enumerable: false, | ||||||
|  | 	}) | ||||||
| 
 | 
 | ||||||
| 	return _constructor | 	return _constructor | ||||||
| } | } | ||||||
| @ -328,5 +292,8 @@ function makeConstructor(name, a, b){ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /********************************************************************** | /********************************************************************** | ||||||
| * vim:set ts=4 sw=4 :                               */ return module }) | * vim:set ts=4 sw=4 :                               */ return module }) | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ig-object", |   "name": "ig-object", | ||||||
|   "version": "1.5.0", |   "version": "2.0.0", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "main": "object.js", |   "main": "object.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user