1

I noticed something while trying to extend Array.prototype. I essentially wanted to write a method which allows for the deletion of the last item in an array:

Array.prototype.removeLast = function() {
    delete this[this.length - 1];
};

This doesn't produce the result I expected:

>>> var arr = [ 1, 2, 3 ];
[ 1, 2, 3 ]
>>> arr.removeLast();
undefined
>>> arr
[ 1, 2, undefined ]

So I tried another method:

Array.prototype.removeLast = function() {
    this.length--;
};

And I got the expected results.

>>> var arr = [ 1, 2, 3 ];
[ 1, 2, 3 ]
>>> arr.removeLast();
undefined
>>> arr
[ 1, 2 ]

Questions

1) Why isn't array-index deletion operating like object-key deletion? (With arrays the reference still seems to exist, but just references undefined. With objects, the reference seems to be deleted entirely.)

2) Is the this.length-- method safe? Could it cause a memory leak, or does altering an object's length attribute also cause a check to run and delete any forgotten indices in the array?

3) Do the answers to either of the previous 2 questions vary based on the implementation?

4) What's a good implementation of removeLast?

Thanks!

Gershom Maes
  • 7,358
  • 2
  • 35
  • 55
  • First of all you shouldn't mutate the Array prototype. Secondly, `delete` removes an object on given index, but doesn't change the length of the array. Thirdly, there are native, better functions for it, like `pop()` or `splice()`, which will change the structure of the array. – kind user Apr 30 '17 at 23:29
  • 1) http://stackoverflow.com/questions/12640216/memory-management-of-javascript-array – ibrahim mahrir Apr 30 '17 at 23:35
  • 2) http://stackoverflow.com/questions/31547315/is-it-an-antipattern-to-set-an-array-length-in-javascript and http://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript – ibrahim mahrir Apr 30 '17 at 23:36
  • 3) and 4) are answered in 1) and 2) – ibrahim mahrir Apr 30 '17 at 23:37
  • While a good reference (from 2012), it's important to note that (1) quotes an old ECMA Standard and furthermore while a standard helps define expectations, it generally does not define how something is implemented (browsers behave differently when the standard is not specific), or when including a feature before it has made it into standard. – vol7ron May 01 '17 at 00:03
  • Also (2) suggests behavior I have seen not to work. `length` at one time was protected in a certain browser. Perhaps enough time as passed to not consider that browser necessary to support, but I disagree with the answer provided, based on my own experience. – vol7ron May 01 '17 at 00:05
  • I should also add that `arr.length=0` is a somewhat common way of manipulating the array (clearing it out), without losing its properties. Again, this conflicts with the point I made above, where a certain legacy browser made *length* immutable. I would gather that it's an edge-case that only needs to be noted and not a concern. – vol7ron May 01 '17 at 00:09

1 Answers1

1

As MDN explains for the deleting array elements:

When you delete an array element, the array length is not affected. This holds even if you delete the last element of the array.

When the delete operator removes an array element, that element is no longer in the array. In the following example, trees[3] is removed with delete.

For your Array, you are trying to delete an index (with it, its value), which is performed using the the delete operator, but not in the way you think. The index/value is removed, but how the JavaScript engine assembles the array and manipulates its properties (e.g., length) will not do what you think. It will still display the missing index w/ undefined, which is what you see.

Demonstration

To better demonstrate, if do Object.keys( your_array ) you will see that the index that you deleted of your array does not exist; likewise, if you perform Object.values( your_array ) you will see that the undefined is not returned. For all intents and purposes you deleted the property (the index) and its associated value.

Other considerations

You may consider using use splice, or pop (if last index), to remove the last element of the array; however, this isn't without recognizing their own effects:

  • splice will reorder the array, shifting the values into new indexes; this is different from delete, which keeps everything at its original index

  • pop will remove only the last item/index from the array

  • splice and pop will both update the length property of the array

Example of delete vs splice vs pop

console.log('\nDELETE');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val)); // notice no undefined


console.log('\nPOP');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.pop();
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val));


console.log('\nSPLICE');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val));

Questions

1) Why isn't array-index deletion operating like object-key deletion? (With arrays the reference still seems to exist, but just references undefined. With objects, the reference seems to be deleted entirely.)

It is.

2) Is the this.length-- method safe? Could it cause a memory leak, or does altering an object's length attribute also cause a check to run and delete any forgotten indices in the array?

Best not to operate and manage the length yourself. Historically, different browsers respond differently to length manipulation.

The only time I've seen length manipulation used in recent years is to clear an array (i.e., arr.length = 0). This is preferred over assigning it to an new empty array (i.e., arr = []) for when the array may contain certain properties that should not be lost or re-constructed.

3) Do the answers to either of the previous 2 questions vary based on the implementation?

Yes

4) What's a good implementation of removeLast?

arr.pop() or arr.splice(-1,1)

vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • _which cannot be performed using the `delete` operator._ Prove it! – ibrahim mahrir Apr 30 '17 at 23:24
  • @ibrahimmahrir I'm actually editing this answer, give me a minute – vol7ron Apr 30 '17 at 23:25
  • I had forgotten about `pop`, and it looks like you've found the part of MDN I'm looking for! But I'm also curious about the potential for a memory-leak resulting from `[].length` modifications. Is `this.length--` an unsafe operation? – Gershom Maes Apr 30 '17 at 23:27
  • 1
    *"Non-configurable properties cannot be removed. This includes properties of built-in objects like Math, Array(...)"* - but he doesn't want to remove a non-configurable property, neither the Array object nor an index. – kind user Apr 30 '17 at 23:32
  • @Kinduser yes you're correct I was in the process of editing as I confused this with another question, which I was answering and copy/pasted the wrong snippet — I think it's updated – vol7ron Apr 30 '17 at 23:43
  • @ibrahimmahrir please instruct how it's wrong. I wasn't expecting you and *Kind user* to evaluate answers so quickly -- good job to both of you! I go through a process of post-edit-save-edit-save-edit-save about 3 edit-review cycles and you caught me at initial one :P well done for being so responsive, the community needs more people like you – vol7ron Apr 30 '17 at 23:50
  • "*The only time I've seen length manipulation used in recent years is to clear an array*" - what else would you say would `removeLast` do if not to clear the last index? `.length--` is totally fine. – Bergi May 01 '17 at 00:22
  • @vol7ron thanks for all the edits! This is the answer I was looking for :D – Gershom Maes May 01 '17 at 00:24
  • @Bergi yes it could do that, but I'd be hesitant to do that over some other means; even when clearing the array via length, I've seen it wrapped in try/catch blocks. It could be my own insecurities, but my opinion -- for repetition, it is my opinion -- is to use an already existing or more popular mechanism that is universally tested and used (e.g., `splice`, `pop`); but I shouldn't be the only one to answer this question, as someone with more practice (in QA/support) may be able to better defend `length--` for the breadth of user agents and CLIs available today. – vol7ron May 01 '17 at 00:46