mirror of
https://github.com/flynx/object.js.git
synced 2025-10-29 02:20:08 +00:00
added ASIS(..) wrapper to help prevent values returned by .__new__(..) from being intergrated into the current object prototype chain enabling constructors to return non-instance values.
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
b77550f97f
commit
077eda6fb3
13
README.md
13
README.md
@ -130,6 +130,7 @@ class B extends A {
|
|||||||
- [`<object>.__call__(..)`](#object__call__)
|
- [`<object>.__call__(..)`](#object__call__)
|
||||||
- [Components](#components)
|
- [Components](#components)
|
||||||
- [`STOP` / `STOP(..)`](#stop--stop)
|
- [`STOP` / `STOP(..)`](#stop--stop)
|
||||||
|
- [`ASIS(..)`](#asis)
|
||||||
- [`Constructor(..)` / `C(..)`](#constructor--c)
|
- [`Constructor(..)` / `C(..)`](#constructor--c)
|
||||||
- [`create(..)` / `Constructor.create(..)`](#create--constructorcreate)
|
- [`create(..)` / `Constructor.create(..)`](#create--constructorcreate)
|
||||||
- [`sources(..)` / `Constructor.sources(..)`](#sources--constructorsources)
|
- [`sources(..)` / `Constructor.sources(..)`](#sources--constructorsources)
|
||||||
@ -508,6 +509,13 @@ no instance exists yet.
|
|||||||
`<context>` is the _outer_ context of the call, i.e. the object from which
|
`<context>` is the _outer_ context of the call, i.e. the object from which
|
||||||
`<constructor>` was referenced before it was called.
|
`<constructor>` was referenced before it was called.
|
||||||
|
|
||||||
|
Any value returned by `.__new__(..)` will be integrated into the prototype
|
||||||
|
chain of `<object>`, if this is not desired then wrap it in
|
||||||
|
[`object.ASIS(..)`](#asis) before returning, but note that this will
|
||||||
|
not prevent `<object>.__init__(..)` from being called. The `ASIS(..)`-wrapped
|
||||||
|
value will be unwrapped before being returned by the constructor.
|
||||||
|
|
||||||
|
|
||||||
For more info see:
|
For more info see:
|
||||||
- [Low level constructor](#low-level-constructor),
|
- [Low level constructor](#low-level-constructor),
|
||||||
- [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects)
|
- [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects)
|
||||||
@ -564,6 +572,11 @@ to stop the search before it reaches the top of
|
|||||||
the prototype chain.
|
the prototype chain.
|
||||||
|
|
||||||
|
|
||||||
|
### `ASIS(..)`
|
||||||
|
|
||||||
|
Can be used in [`.__new__(..)`](#object__new__) to wrap the returned object to
|
||||||
|
prevent changing it's prototype by [`RawInstance()`](#rawinstance).
|
||||||
|
|
||||||
|
|
||||||
### `Constructor(..)` / `C(..)`
|
### `Constructor(..)` / `C(..)`
|
||||||
|
|
||||||
|
|||||||
20
object.js
20
object.js
@ -241,6 +241,15 @@ function(obj){
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Helper objects/constructors...
|
// Helper objects/constructors...
|
||||||
|
|
||||||
|
var ASIS =
|
||||||
|
module.ASIS =
|
||||||
|
function ASIS(value){
|
||||||
|
return {
|
||||||
|
__proto__: ASIS.prototype,
|
||||||
|
value,
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
BOOTSTRAP(function(){
|
BOOTSTRAP(function(){
|
||||||
|
|
||||||
// Error with some JS quirks fixed...
|
// Error with some JS quirks fixed...
|
||||||
@ -647,6 +656,10 @@ function(context, constructor, ...args){
|
|||||||
// default object base...
|
// default object base...
|
||||||
: Reflect.construct(Object, [], constructor)
|
: Reflect.construct(Object, [], constructor)
|
||||||
|
|
||||||
|
// return wrapped object as-is...
|
||||||
|
if(obj instanceof module.ASIS){
|
||||||
|
return obj.value }
|
||||||
|
|
||||||
// link to prototype chain, if not done already...
|
// link to prototype chain, if not done already...
|
||||||
obj.__proto__ !== constructor.prototype
|
obj.__proto__ !== constructor.prototype
|
||||||
&& (obj.__proto__ = constructor.prototype)
|
&& (obj.__proto__ = constructor.prototype)
|
||||||
@ -917,8 +930,11 @@ function Constructor(name, a, b, c){
|
|||||||
_constructor.__rawinstance__(this, ...arguments)
|
_constructor.__rawinstance__(this, ...arguments)
|
||||||
: RawInstance(this, _constructor, ...arguments)
|
: RawInstance(this, _constructor, ...arguments)
|
||||||
// initialize...
|
// initialize...
|
||||||
obj.__init__ instanceof Function
|
// NOTE: we are using _constructor.prototype.__init__ here instead
|
||||||
&& obj.__init__(...arguments)
|
// of obj.__init__ as at this point object may be of a different
|
||||||
|
// type (see RawInstance + ASIS)...
|
||||||
|
_constructor.prototype.__init__ instanceof Function
|
||||||
|
&& _constructor.prototype.__init__.call(obj, ...arguments)
|
||||||
return obj }
|
return obj }
|
||||||
// rename the consructor...
|
// rename the consructor...
|
||||||
// NOTE: we are not using:
|
// NOTE: we are not using:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ig-object",
|
"name": "ig-object",
|
||||||
"version": "6.2.0",
|
"version": "6.2.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "object.js",
|
"main": "object.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
30
test.js
30
test.js
@ -205,7 +205,7 @@ var setups = test.Setups({
|
|||||||
|
|
||||||
// initialization...
|
// initialization...
|
||||||
init: function(assert){
|
init: function(assert){
|
||||||
var A, B, C
|
var A, B, C, D
|
||||||
return {
|
return {
|
||||||
// init...
|
// init...
|
||||||
A: A = assert(object.C('A', {
|
A: A = assert(object.C('A', {
|
||||||
@ -225,6 +225,7 @@ var setups = test.Setups({
|
|||||||
return o
|
return o
|
||||||
},
|
},
|
||||||
test_new: function(){
|
test_new: function(){
|
||||||
|
assert(this instanceof B, 'instanceof correct')
|
||||||
assert(this.new_has_run, '.__new__() run') },
|
assert(this.new_has_run, '.__new__() run') },
|
||||||
}), 'basic .__new__(..)'),
|
}), 'basic .__new__(..)'),
|
||||||
// new + init...
|
// new + init...
|
||||||
@ -622,6 +623,33 @@ var tests = test.Tests({
|
|||||||
|
|
||||||
|
|
||||||
var cases = test.Cases({
|
var cases = test.Cases({
|
||||||
|
'as-is-new': function(assert){
|
||||||
|
var A = object.C('A', {
|
||||||
|
__init__: function(){
|
||||||
|
this.init_A_did_run = true },
|
||||||
|
})
|
||||||
|
var B = object.C('B', {
|
||||||
|
__new__: function(){
|
||||||
|
return object.ASIS(A()) },
|
||||||
|
})
|
||||||
|
|
||||||
|
var b = B()
|
||||||
|
|
||||||
|
assert(b instanceof A, 'not instance of A')
|
||||||
|
assert(!(b instanceof B), 'not instance of B')
|
||||||
|
|
||||||
|
var C = object.C('C', {
|
||||||
|
__new__: function(){
|
||||||
|
return object.ASIS(A()) },
|
||||||
|
__init__: function(){
|
||||||
|
this.init_C_did_run = true },
|
||||||
|
})
|
||||||
|
|
||||||
|
var c = C()
|
||||||
|
|
||||||
|
assert(c.init_A_did_run, 'base .__init__() ran')
|
||||||
|
assert(c.init_C_did_run, 'constructor .__init__() ran')
|
||||||
|
},
|
||||||
'edge-cases': function(assert){
|
'edge-cases': function(assert){
|
||||||
// bad names...
|
// bad names...
|
||||||
assert.error('Constructor(..): malformed name',
|
assert.error('Constructor(..): malformed name',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user