2019-07-16 23:49:32 +03:00
|
|
|
# object.js
|
|
|
|
|
|
2020-05-06 02:37:08 +03:00
|
|
|
_object.js_ provides a meta-constructor and a set of tools and utilities
|
|
|
|
|
to aid in object/instance construction and implementing dynamic data and
|
|
|
|
|
functionality inheritance within the established JavaScript prototypical
|
|
|
|
|
object model and interfaces.
|
2019-07-16 23:49:32 +03:00
|
|
|
|
|
|
|
|
|
2020-04-25 01:14:00 +03:00
|
|
|
This is an alternative to the ES6 `class` syntax in JavaScript and provides
|
2019-07-16 23:49:32 +03:00
|
|
|
several advantages:
|
2020-05-06 03:15:39 +03:00
|
|
|
- Simple way to define instance and "class" (constructor) methods,
|
|
|
|
|
properties and attributes,
|
2020-04-26 21:43:00 +03:00
|
|
|
- Uniform and minimalistic definition syntax based on basic JavaScript
|
|
|
|
|
object syntax, no special cases, special syntax or _"the same but slightly
|
|
|
|
|
different"_ ways to do things,
|
|
|
|
|
- _Transparently_ based on JavaScript's prototypical inheritance model,
|
|
|
|
|
- Granular instance construction (a-la _Python's_ `.__new__(..)`
|
2019-07-16 23:49:32 +03:00
|
|
|
and `.__init__(..)` methods)
|
2020-04-26 21:43:00 +03:00
|
|
|
- Simple way to define callable instances (including a-la _Python's_
|
|
|
|
|
`.__call__(..)`)
|
2020-05-06 03:15:39 +03:00
|
|
|
- produces fully introspectable constructors/instances, i.e. no direct
|
|
|
|
|
way to define "private" attributes or methods.
|
2020-04-26 21:43:00 +03:00
|
|
|
- Less restrictive:
|
2020-05-02 00:48:55 +03:00
|
|
|
- `new` is optional
|
|
|
|
|
- all input components are reusable
|
2020-04-25 02:00:40 +03:00
|
|
|
- no artificial restrictions
|
2019-07-16 23:49:32 +03:00
|
|
|
|
|
|
|
|
Disadvantages compared to the `class` syntax:
|
2020-04-26 21:43:00 +03:00
|
|
|
- No _syntactic sugar_
|
|
|
|
|
- Slightly more complicated calling of `parent` (_super_) methods
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-05-06 03:15:39 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Here is a basic comparison:
|
2020-05-06 02:38:42 +03:00
|
|
|
<table border="0">
|
2020-05-06 02:37:08 +03:00
|
|
|
<tr valign="top">
|
2020-05-06 03:15:39 +03:00
|
|
|
<td width="50%">
|
2020-05-06 02:37:08 +03:00
|
|
|
|
|
|
|
|
_object.js_
|
|
|
|
|
```javascript
|
2020-05-06 03:15:39 +03:00
|
|
|
var L = object.Constructor('L', Array, {
|
2020-05-06 02:37:08 +03:00
|
|
|
constructor_attr: 'constructor',
|
|
|
|
|
|
|
|
|
|
method: function(){
|
|
|
|
|
return 'constructor'
|
|
|
|
|
},
|
|
|
|
|
}, {
|
2020-05-06 03:15:39 +03:00
|
|
|
// prototype attribute (inherited)...
|
2020-05-06 02:37:08 +03:00
|
|
|
attr: 'prototype',
|
|
|
|
|
|
|
|
|
|
get prop(){
|
|
|
|
|
return 42 },
|
|
|
|
|
|
|
|
|
|
__init__: function(){
|
|
|
|
|
this.instance_attr = 7
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2020-05-06 03:15:39 +03:00
|
|
|
- Clear separation of constructor and `.prototype` data:
|
2020-05-06 03:39:32 +03:00
|
|
|
- First block (optional) is merged with `L`,
|
2020-05-06 03:54:10 +03:00
|
|
|
- Second block _is_ the `L.prototype`,
|
2020-05-06 03:39:32 +03:00
|
|
|
- no direct way to do "private" definitions.
|
2020-05-06 03:15:39 +03:00
|
|
|
|
2020-05-06 02:37:08 +03:00
|
|
|
</td>
|
2020-05-06 03:15:39 +03:00
|
|
|
<td>
|
2020-05-06 02:37:08 +03:00
|
|
|
|
|
|
|
|
_ES6_
|
|
|
|
|
```javascript
|
2020-05-06 03:15:39 +03:00
|
|
|
class L extends Array {
|
2020-05-06 02:37:08 +03:00
|
|
|
static constructor_attr = 'class'
|
|
|
|
|
|
|
|
|
|
static method(){
|
|
|
|
|
return 'class'
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 03:15:39 +03:00
|
|
|
// instance attribute (copied)...
|
2020-05-06 02:37:08 +03:00
|
|
|
attr = 'instance'
|
|
|
|
|
|
|
|
|
|
get prop(){
|
|
|
|
|
return 42 }
|
|
|
|
|
|
|
|
|
|
constructor(){
|
|
|
|
|
super(...arguments)
|
|
|
|
|
|
|
|
|
|
this.instance_attr = 7
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2020-05-06 03:39:32 +03:00
|
|
|
- pretty but misleading syntax,
|
|
|
|
|
- `static` and instance definitions are not ordered,
|
2020-05-06 03:15:39 +03:00
|
|
|
- `.attr` is copied to every instance
|
2020-05-06 02:37:08 +03:00
|
|
|
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-05-06 03:15:39 +03:00
|
|
|
|
2020-05-04 01:16:48 +03:00
|
|
|
## Contents
|
|
|
|
|
- [object.js](#objectjs)
|
|
|
|
|
- [Contents](#contents)
|
|
|
|
|
- [Installation](#installation)
|
|
|
|
|
- [Basic usage](#basic-usage)
|
|
|
|
|
- [Inheritance](#inheritance)
|
|
|
|
|
- [Callable instances](#callable-instances)
|
|
|
|
|
- [Advanced usage](#advanced-usage)
|
2020-05-06 05:30:11 +03:00
|
|
|
- [Mix-ins](#mix-ins)
|
2020-05-04 01:16:48 +03:00
|
|
|
- [Low level constructor](#low-level-constructor)
|
|
|
|
|
- [Extending the constructor](#extending-the-constructor)
|
|
|
|
|
- [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects)
|
|
|
|
|
- [Extending native `.constructor(..)`](#extending-native-constructor)
|
|
|
|
|
- [Components](#components)
|
|
|
|
|
- [Utilities](#utilities)
|
|
|
|
|
- [Limitations](#limitations)
|
|
|
|
|
- [Can not mix unrelated native types](#can-not-mix-unrelated-native-types)
|
|
|
|
|
- [License](#license)
|
|
|
|
|
|
2020-04-26 21:49:03 +03:00
|
|
|
|
|
|
|
|
## Installation
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
```shell
|
2020-04-26 21:43:00 +03:00
|
|
|
$ npm install ig-object
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2020-04-26 21:50:56 +03:00
|
|
|
Or just download and drop [object.js](object.js) into your code.
|
2020-04-26 21:49:03 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-05-02 19:55:05 +03:00
|
|
|
## Basic usage
|
2020-04-26 21:49:03 +03:00
|
|
|
|
|
|
|
|
Include the code, this is compatible with both [node's](https://nodejs.org/) and
|
|
|
|
|
[RequireJS'](https://requirejs.org/) `require(..)`
|
2019-07-16 23:49:32 +03:00
|
|
|
```javascript
|
|
|
|
|
var object = require('ig-object')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Create a basic constructor...
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
// NOTE: new is optional here...
|
2020-04-25 02:00:40 +03:00
|
|
|
var A = new object.Constructor('A')
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-05-06 03:39:32 +03:00
|
|
|
var B = object.Constructor('B', A, {})
|
2020-04-25 02:00:40 +03:00
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
var C = object.Constructor('C', B, {})
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
|
|
|
|
|
2020-05-02 19:55:05 +03:00
|
|
|
Now we can test this...
|
2019-07-16 23:49:32 +03:00
|
|
|
```javascript
|
|
|
|
|
var c = C() // or new C()
|
|
|
|
|
|
|
|
|
|
c instanceof C // -> true
|
|
|
|
|
c instanceof B // -> true
|
|
|
|
|
c instanceof A // -> true
|
|
|
|
|
```
|
|
|
|
|
|
2020-04-15 00:42:20 +03:00
|
|
|
|
|
|
|
|
### Inheritance
|
2019-07-16 23:49:32 +03:00
|
|
|
```javascript
|
2020-04-15 00:42:20 +03:00
|
|
|
//
|
2020-05-02 00:48:55 +03:00
|
|
|
// Base <--- Item
|
2020-04-15 00:42:20 +03:00
|
|
|
//
|
2019-07-17 00:26:39 +03:00
|
|
|
var Base = object.Constructor('Base', {
|
2020-05-02 00:48:55 +03:00
|
|
|
proto_attr: 'prototype attr value',
|
2020-04-15 00:42:20 +03:00
|
|
|
|
2020-05-02 00:48:55 +03:00
|
|
|
get prop(){
|
|
|
|
|
return 'propery value' },
|
2020-04-15 00:42:20 +03:00
|
|
|
|
2020-05-02 00:48:55 +03:00
|
|
|
method: function(){
|
|
|
|
|
console.log('Base.method()') },
|
2019-07-17 00:26:39 +03:00
|
|
|
|
2020-05-02 00:48:55 +03:00
|
|
|
// initializer...
|
|
|
|
|
__init__: function(){
|
|
|
|
|
this.instance_attr = 'instance'
|
|
|
|
|
},
|
2019-07-17 00:26:39 +03:00
|
|
|
})
|
|
|
|
|
|
2020-05-06 03:39:32 +03:00
|
|
|
var Item = object.Constructor('Item', Base, {
|
2020-05-02 00:48:55 +03:00
|
|
|
__init__: function(){
|
|
|
|
|
// call the "super" method...
|
|
|
|
|
object.parentCall(this.prototype.__init__, this)
|
2020-04-25 02:00:40 +03:00
|
|
|
|
2020-05-02 00:48:55 +03:00
|
|
|
this.item_attr = 'instance attribute value'
|
|
|
|
|
},
|
2019-07-17 00:26:39 +03:00
|
|
|
})
|
|
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
var SubItem = object.Constructor('SubItem', Item, {
|
|
|
|
|
// ...
|
|
|
|
|
})
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
|
|
|
|
|
2020-04-15 00:42:20 +03:00
|
|
|
|
|
|
|
|
### Callable instances
|
2020-04-25 01:43:31 +03:00
|
|
|
|
2020-04-10 18:30:55 +03:00
|
|
|
```javascript
|
|
|
|
|
var Action = object.Constructor('Action',
|
2020-05-02 00:48:55 +03:00
|
|
|
// constructor as a function...
|
|
|
|
|
function(context, ...args){
|
|
|
|
|
// return the instance...
|
|
|
|
|
return this
|
|
|
|
|
})
|
2020-04-10 18:30:55 +03:00
|
|
|
|
|
|
|
|
var action = new Action()
|
|
|
|
|
|
2020-04-25 02:00:40 +03:00
|
|
|
// the instance now is a function...
|
2020-04-10 18:30:55 +03:00
|
|
|
action()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// a different way to do the above...
|
2020-04-25 01:43:31 +03:00
|
|
|
//
|
|
|
|
|
// This is the same as the above but a bit more convenient as we do
|
|
|
|
|
// not need to use Object.assign(..) or object.mixinFlat(..) to define
|
|
|
|
|
// attributes and props.
|
|
|
|
|
|
2020-04-10 18:30:55 +03:00
|
|
|
var Action2 = object.Constructor('Action2', {
|
2020-05-02 00:48:55 +03:00
|
|
|
__call__: function(context, ...args){
|
|
|
|
|
return this
|
|
|
|
|
},
|
2020-04-10 18:30:55 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2020-04-25 02:08:27 +03:00
|
|
|
In the above cases both the _function constructor_ and the `.__call__(..)`
|
|
|
|
|
method receive a `context` argument in addition to `this` context, those
|
|
|
|
|
represent the two contexts relevant to the callable instance:
|
2020-04-25 02:00:40 +03:00
|
|
|
- Internal context (`this`)
|
2020-04-25 01:43:31 +03:00
|
|
|
This always references the instance being called
|
2020-05-02 00:48:55 +03:00
|
|
|
- External context (`context`)
|
2020-04-25 02:03:42 +03:00
|
|
|
This is the object the instance is called from, i.e. the call _context_
|
|
|
|
|
(`window` or `global` by default)
|
2020-04-25 01:43:31 +03:00
|
|
|
|
|
|
|
|
If the prototype is explicitly defined as a function then it is the
|
2020-04-25 02:05:54 +03:00
|
|
|
user's responsibility to call `.__call__(..)` method.
|
2020-04-25 01:43:31 +03:00
|
|
|
|
|
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
**Notes:**
|
|
|
|
|
- the two approaches (_function_ vs. `.__call__(..)`) will produce
|
|
|
|
|
slightly different results, the difference is in `.prototype`, in the
|
|
|
|
|
first case it is a _function_ while in the second an object with a
|
|
|
|
|
`.__call__(..)` method.
|
|
|
|
|
(this may change in the future)
|
|
|
|
|
|
|
|
|
|
|
2020-05-06 05:30:11 +03:00
|
|
|
### Mix-ins
|
|
|
|
|
|
|
|
|
|
Prototype-based mixin...
|
|
|
|
|
```javascript
|
|
|
|
|
|
|
|
|
|
var utilityMixin = {
|
|
|
|
|
utility: function(){
|
|
|
|
|
// ...
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var Base = object.Constructor('Base')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// mixin directly into the instance...
|
|
|
|
|
var m = object.mixin(Base(), utilityMixin)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`.mixin(..)` will copy the contents of `utilityMixin` into the prototype
|
|
|
|
|
chain between `m` and `m.__proto__`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Constructor-based mixin...
|
|
|
|
|
```javascript
|
|
|
|
|
var UtilityMixin = function(parent){
|
|
|
|
|
return object.Constructor(parent.name + '+utils', parent, utilityMixin) }
|
|
|
|
|
|
|
|
|
|
var Mixed = object.Constructor('Mixed', UtilityMixin(Base), {
|
|
|
|
|
// ...
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var m = Mixed()
|
|
|
|
|
```
|
|
|
|
|
|
2020-05-02 21:48:59 +03:00
|
|
|
|
|
|
|
|
## Advanced usage
|
|
|
|
|
|
2020-04-15 00:42:20 +03:00
|
|
|
### Low level constructor
|
2020-04-25 01:43:31 +03:00
|
|
|
|
2020-04-10 18:30:55 +03:00
|
|
|
```javascript
|
|
|
|
|
var LowLevel = object.Constructor('LowLevel', {
|
2020-05-02 00:48:55 +03:00
|
|
|
__new__: function(context, ...args){
|
|
|
|
|
return {}
|
|
|
|
|
},
|
2020-04-10 18:30:55 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
```
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-04-25 02:08:27 +03:00
|
|
|
Like _function constructor_ and `.__call__(..)` this also has two contexts,
|
2020-04-25 01:43:31 +03:00
|
|
|
but the internal context is different -- as it is the job of `.__new__(..)`
|
2020-04-25 02:08:27 +03:00
|
|
|
to create an instance, at time of call the instance does not exist and `this`
|
2020-04-25 01:43:31 +03:00
|
|
|
references the `.prototype` object.
|
|
|
|
|
The external context is the same as above.
|
|
|
|
|
|
|
|
|
|
Contexts:
|
2020-04-25 02:00:40 +03:00
|
|
|
- Internal context (`this`)
|
2020-04-25 01:43:31 +03:00
|
|
|
References the `.prototype` of the constructor.
|
2020-05-02 00:48:55 +03:00
|
|
|
- External context (`context`)
|
2020-04-25 02:03:42 +03:00
|
|
|
This is the object the instance is called from, i.e. the call _context_
|
|
|
|
|
(`window` or `global` by default), the same as for function constructor
|
|
|
|
|
and `.__call__(..)`.
|
2020-04-25 01:43:31 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
The value `.__new__(..)`returns is used as the instance and gets linked
|
|
|
|
|
in the prototype chain.
|
|
|
|
|
|
|
|
|
|
This has priority over the callable protocols above, thus the user must
|
2020-04-25 02:08:27 +03:00
|
|
|
take care of both the _function constructor_ and `prototype.__call__(..)`
|
2020-04-25 01:43:31 +03:00
|
|
|
handling.
|
|
|
|
|
|
2020-04-26 19:35:35 +03:00
|
|
|
**Notes:**
|
2020-04-26 21:43:00 +03:00
|
|
|
- `.__new__(..)` is an instance method, contrary to _Python_ (the
|
|
|
|
|
inspiration for this protocol). This is done intentionally as in
|
2020-04-26 21:32:13 +03:00
|
|
|
JavaScript there is no distinction between an instance and a class and
|
|
|
|
|
defining `.__new__(..)` in the class would both add complexity as well
|
|
|
|
|
as restrict the use-cases for the constructor.
|
2020-04-26 19:35:35 +03:00
|
|
|
|
2020-04-25 01:43:31 +03:00
|
|
|
|
2020-05-02 22:09:37 +03:00
|
|
|
### Extending the constructor
|
|
|
|
|
|
|
|
|
|
```javascript
|
2020-05-03 03:03:18 +03:00
|
|
|
var C = object.Constructor('C',
|
|
|
|
|
// this will get mixed into the constructor C...
|
|
|
|
|
{
|
|
|
|
|
constructor_attr: 123,
|
|
|
|
|
|
2020-05-02 22:09:37 +03:00
|
|
|
constructorMethod: function(){
|
|
|
|
|
// ...
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ...
|
2020-05-03 03:03:18 +03:00
|
|
|
}, {
|
2020-05-02 22:09:37 +03:00
|
|
|
instanceMethod: function(){
|
2020-05-03 03:03:18 +03:00
|
|
|
// get constructor data...
|
2020-05-02 22:09:37 +03:00
|
|
|
var x = this.constructor.constructor_attr
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
},
|
|
|
|
|
// ...
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
And the same thing while extending...
|
2020-05-02 22:09:37 +03:00
|
|
|
```javascript
|
2020-05-06 03:39:32 +03:00
|
|
|
var D = object.Constructor('D', C,
|
2020-05-03 03:03:18 +03:00
|
|
|
// this will get mixed into C(..)...
|
2020-05-02 22:09:37 +03:00
|
|
|
{
|
|
|
|
|
// ...
|
2020-05-03 03:03:18 +03:00
|
|
|
}, {
|
2020-05-02 22:09:37 +03:00
|
|
|
// ...
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-05-02 22:19:55 +03:00
|
|
|
### Inheriting from native constructor objects
|
2020-05-02 19:55:05 +03:00
|
|
|
|
|
|
|
|
```javascript
|
2020-05-06 03:39:32 +03:00
|
|
|
var myArray = object.Constructor('myArray', Array, {
|
2020-05-02 19:55:05 +03:00
|
|
|
// ...
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2020-05-02 22:19:55 +03:00
|
|
|
All special methods and protocols defined by _object.js_ except for
|
|
|
|
|
`.__new__(..)` will work here without change.
|
|
|
|
|
|
|
|
|
|
For details on `.__new__(..)` and native `.constructor(..)` interaction
|
|
|
|
|
see: [Extending native `.constructor(..)`](#extending-native-constructor)
|
2020-05-02 19:55:05 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
### Extending native `.constructor(..)`
|
|
|
|
|
|
|
|
|
|
Extending `.constructor(..)` is not necessary in most cases as
|
|
|
|
|
`.__init__(..)` will do everything generally needed, except for instance
|
|
|
|
|
replacement.
|
|
|
|
|
|
|
|
|
|
```javascript
|
2020-05-06 03:39:32 +03:00
|
|
|
var myArray = object.Constructor('myArray', Array, {
|
2020-05-02 19:55:05 +03:00
|
|
|
__new__: function(context, ...args){
|
|
|
|
|
var obj = Reflect.construct(myArray.__proto__, args, myArray)
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
return obj
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-07-16 23:49:32 +03:00
|
|
|
## Components
|
|
|
|
|
|
2020-04-25 01:43:31 +03:00
|
|
|
Get sources for attribute
|
2020-04-15 00:42:20 +03:00
|
|
|
```
|
|
|
|
|
sources(<object>, <name>)
|
|
|
|
|
sources(<object>, <name>, <callback>)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <list>
|
2020-04-15 00:42:20 +03:00
|
|
|
```
|
|
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
|
2020-04-30 02:01:00 +03:00
|
|
|
Get parent attribute value or method
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
2020-04-30 02:01:00 +03:00
|
|
|
parent(<prototype>, <name>)
|
|
|
|
|
-> <parent-value>
|
2020-04-27 04:16:35 +03:00
|
|
|
-> undefined
|
|
|
|
|
|
2020-04-30 02:01:00 +03:00
|
|
|
parent(<method>, <this>)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <parent-method>
|
2020-04-27 04:16:35 +03:00
|
|
|
-> undefined
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
|
|
|
|
|
2020-04-30 02:28:08 +03:00
|
|
|
_Edge case: The `parent(<method>, ..)` has one potential pitfall -- in
|
|
|
|
|
the rare case where a prototype chain contains two or more references
|
|
|
|
|
to the same method under the same name, `parent(..)` can't distinguish
|
2020-04-30 02:29:15 +03:00
|
|
|
between these references and will always return the second one._
|
2020-04-30 02:20:29 +03:00
|
|
|
|
|
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
Get parent property descriptor
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
parentProperty(<prototype>, <name>)
|
|
|
|
|
-> <prop-descriptor>
|
|
|
|
|
-> undefined
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-04-27 01:17:42 +03:00
|
|
|
Get parent method and call it
|
|
|
|
|
```
|
2020-04-27 04:16:35 +03:00
|
|
|
parentCall(<prototype>, <name>, <this>)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <result>
|
2020-04-30 02:20:29 +03:00
|
|
|
-> undefined
|
|
|
|
|
|
2020-04-30 02:10:01 +03:00
|
|
|
parentCall(<method>, <this>)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <result>
|
2020-04-27 04:16:35 +03:00
|
|
|
-> undefined
|
2020-04-27 01:17:42 +03:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-04-25 01:43:31 +03:00
|
|
|
Mixin objects into a prototype chain
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
2020-05-02 00:46:51 +03:00
|
|
|
mixin(<root>, <object>, ..)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <object>
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
|
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
|
2020-04-25 01:43:31 +03:00
|
|
|
Mixin contents of objects into one
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
2020-05-02 00:46:51 +03:00
|
|
|
mixinFlat(<root>, <object>, ..)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <object>
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
2020-04-25 01:43:31 +03:00
|
|
|
This is like `Object.assign(..)` but copies property objects rather than
|
|
|
|
|
property values.
|
|
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
|
2020-04-26 21:32:13 +03:00
|
|
|
Make a raw (un-initialized) instance
|
2020-04-26 19:30:49 +03:00
|
|
|
```
|
2020-05-02 00:46:51 +03:00
|
|
|
makeRawInstance(<context>, <constructor>, ..)
|
2020-04-26 19:30:49 +03:00
|
|
|
-> <object>
|
|
|
|
|
```
|
2019-07-16 23:49:32 +03:00
|
|
|
|
2020-05-02 00:46:51 +03:00
|
|
|
A shorthand to this is `Constructor.__rawinstance__(context, ..)`.
|
2020-04-26 19:35:35 +03:00
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
|
2020-04-25 01:43:31 +03:00
|
|
|
Define an object constructor
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
2020-05-02 19:55:05 +03:00
|
|
|
Constructor(<name>)
|
2020-04-10 18:30:55 +03:00
|
|
|
Constructor(<name>, <prototype>)
|
2020-05-03 03:03:18 +03:00
|
|
|
Constructor(<name>, <parent-constructor>, <prototype>)
|
2020-05-06 03:39:32 +03:00
|
|
|
Constructor(<name>, <parent-constructor>, <constructor-mixin>, <prototype>)
|
2020-05-03 03:03:18 +03:00
|
|
|
Constructor(<name>, <constructor-mixin>, <prototype>)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <constructor>
|
2019-07-16 23:49:32 +03:00
|
|
|
```
|
|
|
|
|
|
2020-04-30 16:41:19 +03:00
|
|
|
|
2020-04-25 01:52:00 +03:00
|
|
|
Shorthand to `Constructor(..)`
|
|
|
|
|
```
|
|
|
|
|
C(<name>, ..)
|
2020-05-02 00:48:55 +03:00
|
|
|
-> <constructor>
|
2020-04-25 01:52:00 +03:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-05-03 03:11:36 +03:00
|
|
|
|
|
|
|
|
## Utilities
|
|
|
|
|
|
|
|
|
|
Align text to shortest leading whitespace
|
|
|
|
|
```
|
|
|
|
|
normalizeIndent(<text>)
|
|
|
|
|
normalizeIndent(<text>, <tab-size>)
|
|
|
|
|
-> <text>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is used to format `.toString(..)` return values for nested functions
|
|
|
|
|
to make source printing in console more pleasant to read.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-05-03 03:03:18 +03:00
|
|
|
## Limitations
|
|
|
|
|
|
2020-05-04 01:16:48 +03:00
|
|
|
### Can not mix unrelated native types
|
2020-05-03 03:03:18 +03:00
|
|
|
|
2020-05-03 03:11:36 +03:00
|
|
|
At this point we can't mix native types, for example it is not possible
|
|
|
|
|
to make a callable `Array` object...
|
2020-05-03 03:03:18 +03:00
|
|
|
|
2020-05-03 15:18:41 +03:00
|
|
|
This is not possible in current _JavaScript_ implementations directly
|
|
|
|
|
as most builtin objects rely on "hidden" mechanics and there is no way
|
|
|
|
|
to combine or inherit them.
|
|
|
|
|
|
|
|
|
|
To illustrate:
|
2020-05-03 03:03:18 +03:00
|
|
|
```javascript
|
2020-05-03 15:18:41 +03:00
|
|
|
// produces an Array that looks like a function but does not act like one...
|
|
|
|
|
var a = Reflect.construct(Array, [], Function)
|
|
|
|
|
|
|
|
|
|
// creates a function that looks like an array...
|
|
|
|
|
var b = Reflect.construct(Function, [], Array)
|
2020-05-03 03:03:18 +03:00
|
|
|
```
|
|
|
|
|
|
2020-05-03 15:18:41 +03:00
|
|
|
So these will produce partially broken instances:
|
2020-05-03 03:03:18 +03:00
|
|
|
```javascript
|
2020-05-03 15:18:41 +03:00
|
|
|
var A = object.Constructor('A', Array, function(){ .. })
|
|
|
|
|
|
|
|
|
|
var B = object.Constructor('B', Array, {
|
2020-05-03 03:03:18 +03:00
|
|
|
__call__: function(){ .. },
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2020-05-03 15:18:41 +03:00
|
|
|
Essentially this issue and the inability to implement it without
|
|
|
|
|
emulation, shows the side-effects of two "features" in _JavaScript_:
|
|
|
|
|
- lack of multiple inheritance
|
|
|
|
|
- _hidden_ protocols/functionality (namely: calls, attribute access)
|
|
|
|
|
|
|
|
|
|
Still, this is worth some thought.
|
2020-05-03 03:03:18 +03:00
|
|
|
|
|
|
|
|
|
2019-07-16 23:49:32 +03:00
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
[BSD 3-Clause License](./LICENSE)
|
|
|
|
|
|
2019-07-17 00:26:39 +03:00
|
|
|
Copyright (c) 2019, Alex A. Naanou,
|
2019-07-16 23:49:32 +03:00
|
|
|
All rights reserved.
|
|
|
|
|
|
2020-04-25 01:14:00 +03:00
|
|
|
<!-- vim:set ts=4 sw=4 spell : -->
|