Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

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?

share|improve this question
    
possible duplicate of How to empty an array in JavaScript? – levi Jul 21 '15 at 19:07
4  
@levi Is that really a duplicate? It is definitely related, but that's not really what the OP is asking. – Josh Crozier Jul 21 '15 at 23:17
7  
I recommend changing the title of the question. "Is it an antipattern" is an entirely different question than the two you stated in the text of your question, and whether something is an antipattern or not is subjective and probably not an appropriate question for Stack Overflow for that reason. – Justin Lardinois Jul 22 '15 at 1:38
1  
@Justin Lardinois, what would be a better title? – Fluffy Jul 22 '15 at 8:01
1  
I believe this question belongs to codereview – Panther Jul 22 '15 at 10:36
up vote 14 down vote accepted

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
share|improve this answer

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

share|improve this answer
2  
1+ Nice answer. Hopefully it get some views now that the question is on the "Hot Network Questions" list. – Josh Crozier Jul 21 '15 at 23:18
    
For those arguing that it is an antipattern, what (semantically equivalent) would they suggest to use instead? – Bergi Jul 22 '15 at 4:13

As it is writeable https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length (seen here) It should be okay to use it that way

You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements does not increase; for example, if you set length to 3 when it is currently 2, the array still contains only 2 elements.

There's even an example how to shorten an array, using this on Mozilla Developer Network

if (statesUS.length > 50) {
    statesUS.length = 50;
}
share|improve this answer
3  
That example is silly; the if check is totally unnecessary! – Seiyria Jul 21 '15 at 23:24
8  
@Seiyria: not if there's the possibility of also handling lists of US states less than 50 states long (e.g. if dealing with historical data from when the US had less than 50 states, or just handling some subset of states). In that case, if you just set the length to 50 without the check, you'd end up with empty junk entries at the end. – Mac Jul 21 '15 at 23:45
1  
@Mac According to the quote in this answer, no, you wouldn't, would you? If you have an array of length 40, and set its length to 50, then according to this answer, the array still has only 40 elements. – hvd Jul 22 '15 at 7:37
1  
[unrelated to question] Be very wary of the example given. If you've a list with a number of valid values (in this case, 50 valid values, as there are 50 states), truncating the array is a REALLY BAD way to ensure that you have legal values. Say you' are grouping addresses by state, and want to ignore addresses from Washington DC and Guam and various other territories, allowing only the 50 states. In that case, run through your array, swapping each invalid entry to the end as you find it, and truncating by one. Truncating alone will throw away legal values, and keep bad ones. – Dewi Morgan Jul 22 '15 at 7:59
1  
@hvd but if you iterate over the thing after the mischief you will find undefined extra stuff – mccc Jul 22 '15 at 11:01

It's better to use slice because your intentions are clear.

var truncated = a.slice(0,2)

Slice does create a new array though.

If that is an issue for you then there is nothing wrong with modifying the length property.

It's actually the fastest way of truncation and supported in all browsers. jsperf

share|improve this answer
1  
.slice creates a new array though. – Felix Kling Jul 21 '15 at 19:02
2  
I suppose you're suggesting the pattern of usage a = a.slice(0,20)? But Array.prototype.slice is intended for copying, and it's not outrightly clear that it can be used to achieve deletion of elements. Just my own opinion. – Igwe Kalu Jul 21 '15 at 19:02
    
@IgweKalu very good point – Miguel Mota Jul 21 '15 at 19:09

Is it an antipattern to set array length in JavaScript?

No. It would be OK to set it to truncate the array.

Does it have decent browser support?

Yes, see the compatiblity matrix here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length

Do the removed values get garbage collected properly?

Yes, they should. Will they actually get gced - you will need to profile the JavaScript code if this is a real concern.

share|improve this answer

This way of truncating an array is mentioned in JavaScript: Good Parts, so it is not an anti-pattern.

share|improve this answer
    
There are many books on the market that advocate antipatterns… – Bergi Jul 22 '15 at 4:14
1  
@Bergi - Agreed. But Crockford's book is not just one of the books on the market. – Pol Jul 22 '15 at 6:43

It is not an anti pattern. It is supported in all major browsers. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length

share|improve this answer
1  
Support has nothing to do about whether something is an anti-pattern or not. – Quentin Jul 22 '15 at 10:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.