-
-
Save jasuperior/807ace24838ca5b45fe42d8e5d36f420 to your computer and use it in GitHub Desktop.
class Rrray extends Array { | |
constructor(){ | |
super(...arguments); | |
this.index = {} | |
return new Proxy(this, this.handler); | |
} | |
get handler () { | |
let $self = this; | |
return { | |
get(target, prop, proxy){ | |
let Num = target.isNum(prop); | |
if(typeof prop == "symbol"){ | |
if(typeof target[prop] == "function") | |
return target[prop].bind(target) | |
return target[prop] | |
} | |
let reg = /(\$|_)(\d+)/; | |
let indexes = prop.match(reg); | |
if(indexes){ | |
if(indexes[1] == "$"){ | |
return proxy[indexes[2]] | |
}else if (indexes[1]=="_"){ | |
return proxy["-"+indexes[2]] | |
} | |
} | |
/*Every alternation results in a call to this.makeValue, which creates a synthetic Rrray with a default .value | |
property which represents the value of the provided index, and a relative "space" which is an Rrray | |
which represents all indexes surrounding your value*/ | |
if(Num||Num===0){ | |
if(Num > -1){ | |
let left = target.slice(0,Num)||[]; //slice the left values to the left and right of target value. | |
let right = target.slice(Num+1)||[]; | |
return target.makeValue( | |
target[Num], //supply the value of the index | |
new Rrray(...[target[Num],...right,...left]), //a rearranged Rrray for the space | |
Num //the index of the value | |
); | |
}else{ | |
Num = target.length + Num; | |
let left = target.slice(0,Num)||[]; | |
let right = target.slice(Num+1)||[]; | |
return target.makeValue( | |
target[Num], | |
new Rrray(...[target[Num],...right,...left]), | |
Num | |
); | |
} | |
}else{ | |
if(typeof target[prop] == "function"){ | |
return target[prop].bind(target); | |
} | |
let index = target.index[prop]; | |
if(index||index===0){ | |
if(index > -1){ | |
let left = target.slice(0,index)||[]; | |
let right = target.slice(index+1)||[]; | |
return target.makeValue( | |
target[index], | |
new Rrray(...[target[index],...right,...left]), | |
index | |
); | |
} else{ | |
index = target.length + index; | |
let left = target.slice(0,index); | |
let right = target.slice(index+1); | |
return target.makeValue( | |
target[index], | |
new Rrray(...[target[index],...right,...left]), | |
index | |
) | |
} | |
} | |
} | |
}, | |
set( target, prop, value ) { | |
let $value = target.isNum(value), $prop = target.isNum(prop); | |
if((!$prop && $prop !== 0)){ | |
if(!$value && $value !== 0){ | |
target.push(value); | |
target.index[prop] = target.length-1; | |
} | |
else target.index[prop] = value; | |
} | |
if($prop || $prop === 0){ | |
target[$prop>-1?$prop:target.length+$prop] = value; | |
} | |
return true; | |
}, | |
getPrototypeOf (){ | |
return Rrray.prototype; | |
} | |
} | |
} | |
makeValue( value, space = new Rrray(), index) { | |
/* creates a value type which when used as a primitive expresses the value of the slot, | |
if accessing a property or index, it will source from the space array (the constructed Rrray of relative values) */ | |
let $self = this; | |
return new Proxy({value, space, index}, { | |
get( target, prop){ | |
if(prop == "value") return target.value; | |
if(prop == "index") return target.index; | |
let value; | |
if(prop == Symbol.toPrimitive) return ()=> (target.value && target.value.valueOf()); | |
if(typeof target.space[prop] == "function") return target.space[prop].bind(target.space); | |
return target.space[prop]?target.space[prop]:target.value?target.value[prop]:undefined; | |
}, | |
set(target, prop, value) { | |
let num = $self.isNum(prop); | |
if(num === 0){ | |
target.value = value; | |
prop = num; | |
} | |
target.space[prop] = value; | |
return true; | |
}, | |
getPrototypeOf (){ | |
return Rrray.prototype; | |
} | |
}) | |
} | |
isNum ( prop ) { | |
if(typeof prop == "symbol") return; | |
return !isNaN(prop)&&parseInt(prop); | |
} | |
set(prop, value) { | |
} | |
} | |
var arr = new Rrray(0,1,2,3,4,5,6,7,8,9); | |
console.log(arr[0] == 0) //true | |
console.log(arr[-1] == 9)//true | |
console.log(arr[3][-5] == 8) //true | |
//All new properties, are pushed to the back of the array, and given an index. Thus, all properties have access to its siblings | |
//as well | |
arr.person = "Susan"; | |
console.log(arr.person == "Susan"); | |
console.log(arr.person.index == 10); //all values have an index property which is it's index in the array. | |
console.log(arr.person[-1] == 9); | |
arr.person_number = -2; //setting a property to a value will point the property to that index, rather than setting it to the value; | |
console.log(arr.person_number == 9, +arr.person_number == +arr.person[-1]); // "+" symbol added to force number typing. (Stupid js equivilency). | |
console.log(arr.person_number.index == 9); | |
//Also there is a special way to call indexes as normal property values by prefixing _ before the number for negative values | |
//and $ for positive values | |
//This is especially useful when having to destructure for a function, and needing to know the relative values of a given value | |
function test ( { _1, $1, $5 } ){ | |
console.log( _1 + $1 + $5 ) | |
} | |
test(arr); //Susan15 | |
test(arr.person) //13; | |
Hey thanks this helped me with a problem I was having https://stackoverflow.com/questions/64996534/is-is-possible-to-pass-this-context-into-an-es6-proxy-handler
@edzillion
Hehehe... no problem. I know it’s not necessarily the cleanest solution, but at the time it was the easiest way I could come up with to attack I dance variables on a proxy.
Now, I would probably handle this with a function. Pass in the values and apply it to an object and return a proxy over the created object.
It gets rid of the confusion that arises when class validation. The code would have you believe that the object your returned after a new Rray
is an Rray, but it’s actually a proxy, so it will fail all validation.
With the functional method, there return value always determines the type of the function... so it’s all compliant. Even one better, it plays nicely with typescript, returning a Proxy<UnderlyingClass>
which is more coherent and descriptive of the object you have.
Hey thanks this helped me with a problem I was having https://stackoverflow.com/questions/64996534/is-is-possible-to-pass-this-context-into-an-es6-proxy-handler