I am working on an essentially very simple script that is supposed to do the following:
- Loop over all Rectangles in a document
- If certain criteria are met, make a copy of the current rectangle (on a different layer) and do some stuff with it
I can loop over the app.activeDocument.rectangles collection with no problem, but as soon as I duplicate an individual Rectangle object, the loop break. It seems that duplicating an element unshifts the copy onto the beginning of the array of objects represented by the Rectangles collection, rather than pushing it onto the end.
So if I have three Rectangle objects in the document (let’s make them red, green and blue, just to tell them apart), I’d initially get a collection like this:
- Rectangles[0]: redBox
- Rectangles[1]: greenBox
- Rectangles[2]: blueBox
I loop over the collection and copy the current object on each iteration like so:
var els = app.activeDocuments.rectangles;
var targetLayer = app.activeDocument.layers.itemByName("Target Layer");
for (i = 0, j = els.length; i < j; i++) { var orgEl = els[i]; var newEl = orgEl.duplicate(targetLayer); $.writeln(i + ": " + orgEl.id + " / " + newEl.id); // do more stuff with the duplicated element here
}
Doing this, I would (naïvely) expect the collection to end up looking like this:
- Rectangles[0]: redBox
- Rectangles[1]: greenBox
- Rectangles[2]: blueBox
- Rectangles[3]: redBox Copy
- Rectangles[4]: greenBox Copy
- Rectangles[5]: blueBox Copy
– but instead this is what happens:
- Rectangles[0]: redBox Copy
- Rectangles[1]: redBox Copy
- Rectangles[2]: redBox Copy
- Rectangles[3]: redBox
- Rectangles[4]: greenBox
- Rectangles[5]: blueBox
In other words, when I call orgEl.duplicate() in the first iteration (i = 0), the duplicated element is unshifted into the collection at position 0, and the current element’s index is moved up one, becoming 1. On the next iteration (i = 1), naturally, I get the same element again, since its position has moved since the start of the loop.
Now, it is of course possible to overcome the obstacle that this presents for looping over collections, by doing this for example:
var els = app.activeDocuments.rectangles;
var ids = els.everyItem().id;
var targetLayer = app.activeDocument.layers.itemByName("Target Layer");
for (i = 0, j = els.length; i < j; i++) { var orgEl = ids[i]; var newEl = orgEl.duplicate(targetLayer); $.writeln(i + ": " + orgEl.id + " / " + newEl.id); // do more stuff with the duplicated element here
}
But that’s rather unintuitive and cumbersome. I can think of several good reasons why duplicating an element onto the end of a collection would be usual and make sense, but I cannot think of a single good reason why adding it on to the beginning. All the effects I can think of are negative: the weirdness of modifying the index position of the current element, the rather significant performance hit that comes with unshifting compared to pushing, and just… general common sense.
So why is it that duplicate() apparently unshifts rather than pushing? Is there some logical reasoning behind this seemingly counterintuitive decision?