Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it an antipattern to set an array length in JavaScript?

Tags:

javascript

Is it bad to use code like:

var a = [1,2,3,4]; a.length = 2; // 3 and 4 are removed 

Does it have decent browser support? Do the removed values get garbage collected properly?

like image 991
Fluffy Avatar asked Jul 21 '15 18:07

Fluffy


People also ask

Can you change the length of an array in JavaScript?

JavaScript allows you to change the value of the array length property. By changing the value of the length, you can remove elements from the array or make the array sparse.

Do you have to declare array size in JavaScript?

Regarding your comment: In JS you don't need to initialize the length of the array. It grows dynamically. You can just store the length in some variable, e.g.

Is an array length fixed?

A fixed array is an array for which the size or length is determined when the array is created and/or allocated. A dynamic array is a random access, variable-size list data structure that allows elements to be added or removed. It is supplied with standard libraries in many modern programming languages.

Why is array length not a method JavaScript?

Length is not a method, it is a property. It doesn't actually do anything but return the length of an array, a string, or the number of parameters expected by a function. When you use . length, you are just asking the JavaScript interpreter to return a variable stored within an object; you are not calling a method.


2 Answers

Does it have decent browser support?

Yes. This has been present since the very first edition of ECMAScript:

Specifically, whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted.

Standard ECMA-262, 15.4

In ECMAScript 5, this was moved to 15.4.5.2.

Attempting to set the length property of an Array object to a value that is numerically less than or equal to the largest numeric property name of an existing array indexed non-deletable property of the array will result in the length being set to a numeric value that is one greater than that largest numeric property name.

Standard ECMA-262, 15.4.5.2

All browsers support this behavior.


Do the removed values get garbage collected properly?

Yes. (See quotes above, and 15.4.5.1.)


Is it an antipattern to set array length in Javascript?

No, not really. While arrays are "exotic objects" in ES6-speak, the real crazily unique thing about arrays are their indexing, not setting the length property. You could replicate the same behavior with a property setter.

It's true that property setters with non-subtle effects are somewhat unusual in JS, as their side-effects can be unobvious. But since .length has been there in Javascript from Day 0, it should be fairly widely understood.

If you want an alternative, use .splice():

// a is the array and n is the eventual length  a.length = n;  a.splice(n, a.length - n); // equivalent a.splice(n, a.length);     // also equivalent 

If I were avoid setting .length for some reason, it would be because it mutates the array, and I prefer immutable programming where reasonable. The immutable alternative is .slice().

a.slice(0, n);  // returns a new array with the first n elements 
like image 185
Paul Draper Avatar answered Sep 24 '22 06:09

Paul Draper


Arrays are exotic objects.

An exotic object is any form of object whose property semantics differ in any way from the default semantics.1

The property semantics for arrays are special, in this case that changing length affects the actual contents of the array.

An Array object is an exotic object that gives special treatment to array index property keys [...] 2

The behavior of the specific property key for this array exotic object is outlined as well.

[...] Every Array object has a length property whose value is always a nonnegative integer less than 2^32. The value of the length property is numerically greater than the name of every own property whose name is an array index; whenever an own property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant [...]

This section is detailing that the length property is a 32 bit integer. It is also saying that if an array index is added, the length is changed. What this is implying is that when an own property name that is not an index is used, the length is not changed and also that names which are not indexes are considered numerically less than the indexes. This means that if you have an array and also add a string (not implicitly numeric either, as in not "3") property to it, that changing the length to delete elements will not remove the value associated with the string property. For example,

var a = [1,2,3,4]; a.hello = "world"; a.length = 2; // 3 and 4 are removed console.log(a.hello);//"world" 

[...] Specifically, whenever an own property is added whose name is an array index, the value of the length property is changed, if necessary, to be one more than the numeric value of that array index; [...]

In addition to the truncation, expansion is also available by use of an index. If an index value is used (an integer basically) then the length will be updated to reflect that change. As arrays in JavaScript are sparse (as in, no gaps allowed) this means that adding a value for a larger index can make an array rather larger.

var a = [1,2,3,4]; a[50] = "hello"; console.log(a.length);//51 

[...] and whenever the value of the length property is changed, every own property whose name is an array index whose value is not smaller than the new length is deleted.

Finally, this is the specific aspect in question which the OP raises. When the length property of an array is modified, it will delete every index and value which is numerically more than the new length value minus 1. In the OP's example, we can clearly see that changing the length to 2 removed the values at index 2 and 3, leaving only the first two values who had index 0 and 1.

The algorithm for the deletion mentioned above can be found in the ArraySetLength(A, Desc) definition.

  1. b. Let deleteSucceeded be A.[[Delete]](ToString(oldLen)). 3

Which is converting the index to a string and using the delete behavior for objects on the index. At which point the entire property is removed. As this internally reaches the delete call, there is no reason to believe that it will leak memory or even that it is an anti pattern as it is explicitly described in the language specification.

In conclusion, Does it have decent browser support? Yes. Do the removed values get garbage collected properly? Yes.

However, is it an anti-pattern? This could be argued either way. What it really breaks down to is the level of familiarity with the language of others who would be using the same code which is a nice way of saying that it may not have the best readability. On the other hand, since JavaScript does take up bandwidth or memory with each character used (hence the need for minification and bundling) it can be useful to take this approach to truncate an array. More often than not, worrying about this type of minutia is going to be a micro-optimization and the use of this special property should be considered on a case to case basis in context with the overall design of the related code.

1. The Object Type ECMA 6
2. Array Exotic Objects ECMA 6
3. ArraySetLength(A, Desc) ECMA 6

like image 40
Travis J Avatar answered Sep 24 '22 06:09

Travis J