Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Array.pop() mess array's length?

Tags:

javascript

I am trying the following code in ideone:

var a = [];
a[0] = 0;
a[5] = 5;
a[6] = undefined;
print("contents before popping:");
for(var e in a) print("\ta[", e, "] =", a[e]);
print("a.length =", a.length);
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i));

print("popping -->", a.pop());
print("popping -->", a.pop());
print("contents after popping:");
for(var e in a) print("\ta[", e, "] =", a[e]);
print("a.length =", a.length);
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i));

The output goes as follows:

contents before popping:
    a[ 0 ] = 0
    a[ 5 ] = 5
    a[ 6 ] = undefined
a.length = 7
    a.hasOwnProperty( 0 ) = true
    a.hasOwnProperty( 1 ) = false
    a.hasOwnProperty( 2 ) = false
    a.hasOwnProperty( 3 ) = false
    a.hasOwnProperty( 4 ) = false
    a.hasOwnProperty( 5 ) = true
    a.hasOwnProperty( 6 ) = true
popping --> undefined
popping --> 5
contents after popping:
    a[ 0 ] = 0
a.length = 5
    a.hasOwnProperty( 0 ) = true
    a.hasOwnProperty( 1 ) = false
    a.hasOwnProperty( 2 ) = false
    a.hasOwnProperty( 3 ) = false
    a.hasOwnProperty( 4 ) = false

In my JavaScript book (well, Crockford's) I read that array's length is calculated as the biggest numerical value of all properties. So, why does it say the length is 5 when the biggest numerical property it has is 0? Thanks!

like image 704
Roman Saveljev Avatar asked Apr 07 '13 10:04

Roman Saveljev


People also ask

Is Pop () destructive?

push() , pop() , shift() and unshift() are only four of many other such methods. These four array methods are quite similar to each other in the way they work and the fact that they are all destructive.

Does pop modify the original array?

JavaScript Array pop()The pop() method changes the original array. The pop() method returns the removed element.

Can I pop from an array?

Use the pop() method to remove the last element of an array. Use the call() or apply() to call the pop() method on an array-like object.

Does splice change array length?

splice alters the length of an array.


2 Answers

A nice thing about Javascript is that its semantics is formally and as unambiguously as possible defined in the standard. Specifically, section 15.4 states that:

The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant.

In other words, everytime you change an array, its length is adjusted, however, it's only guaranteed to be greater than max(indexes), and not necessarily equal to max(indexes)+1. For example, the pop method always removes the length-1'th element and decrements length by one, no matter how many elements an array actually contains.

Also do note that most array methods are generic and don't "know" anything about arrays specifically. They can manipulate arbitrary objects, and if such an object happens to have a property named length, it will be adjusted according to the above rule. Consider:

foo = {
    length: 100,
    99: 'hi'
}

alert([].pop.apply(foo)) // hi
alert(foo.length)        // 99

alert([].pop.apply(foo)) // undefined
alert(foo.length)        // 98

That is, in the context of your question it's irrelevant how exactly arrays are represented - pop and friends don't use this information.

like image 84
georg Avatar answered Sep 17 '22 23:09

georg


The "problem" is the assignment of 5.

The second you do that, the Javascript Array gets filled up with slots which get initialized with the undefined value.

So calling

a[5] = 5;

causes

[0, undefined, undefined, undefined, undefined, 5]

Then you create also a[6] and initialize it with undefined and we get

[0, undefined, undefined, undefined, undefined, 5, undefined]

.length of 7.

Now we call a double .pop() (love the word doublepop) and we get

[0, undefined, undefined, undefined, undefined]

.length of 5


Actually, as pointed out in the comments, this still seems to be very odd behavior. When initializing any index, the slots before are not really assigned by anything. It creates a sparse array. But then again, if we remove the last two entries, there is only one value left (0) followed by undefined values (which somehow became real values, probably because we assigned a 6 manually).

I guess we need an implementation Guru :)

like image 26
jAndy Avatar answered Sep 18 '22 23:09

jAndy