context
I created an array docket
to keep track of coordinates as the user clicks on a canvas space. During the main program loop the array is to be scanned by a draw function so that selected pixels can be seen. Originally, inside of my event listener, I was using the push( )
method but then I realized I wanted a way to sort of toggle the pixels.
code description
So I added a method poke( )
to Array.prototype
, as seen below, which allows me to push the whole docket
array into a local array param.array
and assign the trigger coordinate to a local variable param.entry
. entry
is then pushed into array
and array
is processed by the main poke( )
loop to ensure there are no duplicate values. If a match is found, both elements are annihilated and param.array
is returned to the top, ultimately shrinking docket
by 1; If no matches are found then no elements are annihilated and param.array
is returned to the top, ultimately expanding docket
by 1.
main issue: example 1
Anyway, as the method is currently written, it must be called thusly:
docket.poke( docket, e.key );
Note: for simplicity I have used keyboard key values.
Array.prototype.poke = function( a, b ) {
var bool = { }, i = { }, param = { };
param.array = a; param.entry = b;
//
param.array.push( param.entry );
i.len = param.array.length;
i.end = i.len - 1;
//
for ( i.cur = 0; i.cur < i.len; i.cur++ ) {
bool.match = param.array[ i.cur ] == param.array[ i.end ];
bool.nSelf = !( i.cur == i.end );
//
if ( bool.match && bool.nSelf ) {
param.array.splice( i.end, 1 );
param.array.splice( i.cur, 1 );
//
i.end -= 2;
i.len -= 2;
}
}
//
return param.array;
}
This seems a little redundant, but it offers two critical advantages. First to readability and aesthetic. Being able to visibly pass off the contents of docket
to a local array for processing and then visibly return the results to the top I think is very helpful to comprehension. Second, both this example and the next use a sort of confusing truth test to filter out false positives on duplicate value detection. This example doesn't have too though. It could easily be rewritten to compare each element in param.array
to param.entry
using a tight, no nonsense for loop.
main issue: example 2
docket.poke( e.key );
is the less redundant and more desired approach. This is my code.
Array.prototype.poke = function( a ) {
var bool = { }, entry = a, i = { };
//
this.push( entry );
i.len = this.length;
i.end = i.len - 1;
//
for ( i.cur = 0; i.cur < i.len; i.cur++ ) {
bool.match = this[ i.cur ] == this[ i.end ];
bool.nSelf = !( i.cur == i.end );
//
if ( bool.match && bool.nSelf ) {
this.splice( i.end, 1 );
this.splice( i.cur, 1 );
//
i.end -= 2;
i.len -= 2;
}
}
}
As you can see, this eliminates the the redundancy in the call, but it sacrifices some readability of the method and more importantly the opportunity to really slim up the code using the simple comparison I mentioned above.
So now I'm wondering if there is some less than obvious way that I've missed which will allow me to pass the full contents of my array to a local variable without having to first pass them in as a parameter of its own method.
Any ideas?
There is no reason to define the method on the prototype if you are going to pass the array as an argument. A plain function would be just fine for that.
The second version of your code has indeed the advantage that you can apply the method to a given array instead of passing the array to a function.
The code could however be simplified if:
indexOf
:Array.prototype.toggle = function(value) {
var index = this.indexOf(value);
if (index > -1) {
this.splice(index, 1);
} else {
this.push(value);
}
}
var a = [4,2,5,8];
a.toggle(2);
console.log(a.join());
a.toggle(2);
console.log(a.join());
NB: I personally find the name toggle
more telling than poke
.
Consider also the power of a Set
: it will find an existing member in constant time (while an array implementation needs linear time), and will also be able to remove it in constant time. So if you are open to using something else than an array for this, go for a Set
.
Set.prototype.toggle = function(value) {
if (!this.delete(value)) this.add(value);
}
var a = new Set([4,2,5,8]);
a.toggle(2);
console.log([...a].join());
a.toggle(2);
console.log([...a].join());