0

When you're iterating over a javascript array using forEach, the object (obj in the example below) can be modified, and it will alter the original object in the array.

But if you delete it, why doesn't it remove it from the array? The following code doesn't appear to modify the array at all.

var myArr = [{test: 1},{test2: 2}];
console.log("before", myArr);
myArr.forEach(function(obj) {
   delete obj;
});
console.log("after", myArr);
Doug Molineux
  • 12,283
  • 25
  • 92
  • 144
  • possible duplicate of [Deleting Objects in JavaScript](http://stackoverflow.com/questions/742623/deleting-objects-in-javascript) – Oriol Aug 28 '14 at 16:32
  • Just a suggestion: Just free yourself of all the hassle and use underscore or lodash which in this case you simply use the reject function for. lodash.com/docs (such an easy tool for working with objects and collections). Last thing you need in a large application is a 6 line ugly for loop for a remove method – makeitmorehuman Aug 28 '14 at 16:35
  • @XGreen - library is a good option but fundamentals are more important. – Liam Aug 28 '14 at 16:49
  • can't argue with that – makeitmorehuman Aug 28 '14 at 16:51
  • delete myArr[myArr.indexOf(obj)]; will delete the property - see my answer – Liam Aug 28 '14 at 17:01

4 Answers4

4

delete removes properties, it doesn't destroy the value associated with a property.

delete obj is just trying (and failing) to remove the local variable obj from the current activation record.

It fails because an activation record, though it is an object, cannot have properties removed in this way.

One way to tell when a delete fails is to look at its return value, which is a boolean where true indicates that there is no such property/binding after the delete completes:

if (delete obj) {
  alert('the obj property was deleted');
} else {
  alert('delete did nothing');
}

Put that inside (function () { var obj; ... })() and it will tell you that it did nothing.

Put that inside with ({ obj: null }) { ... } and it will tell you that it worked.

In strict mode, any delete that would return false should instead raise an exception, and deletes that can never work should result in a parse-time error.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • Relevant: http://es5.github.io/#x10.2.1.1.5. But I haven't found anything in the spec that explains when a binding is deletable. Do you have any info about that? – Felix Kling Aug 28 '14 at 16:35
  • @FelixKling, quite right. I thought that relates to the builtin *[[Configurable]]*. – Mike Samuel Aug 28 '14 at 16:36
  • @FelixKling, [#x11.4.1](http://es5.github.io/#x11.4.1) has a non-normative note re *[[Configurable]]* – Mike Samuel Aug 28 '14 at 16:38
  • But only properties can be [[Configurable]]? Or am I wrong? I'm explicitly talking about bindings (of an environment record). – Felix Kling Aug 28 '14 at 16:38
  • [The *DeleteBinding* Concrete method](http://es5.github.io/#x10.2.1.1.5) explains EnvironmentRecord binding deletion. – Mike Samuel Aug 28 '14 at 16:39
  • Yes, that's the link I posted in my first comment ;) And it says *"If the binding for N in envRec is cannot be deleted, return false."*. And my question was: "What makes a binding not deletable?" – Felix Kling Aug 28 '14 at 16:41
  • 1
    @FelixKling, sorry, you're right. I think [#10.5](http://es5.github.io/#x10.5) explains the conditions under which *configurableBindings* is true for a binding environment which affects the results of creation of bindings for that environment. – Mike Samuel Aug 28 '14 at 16:48
  • Ah thank you. I overlooked the part *"If D is true record that the newly created binding may be deleted by a subsequent DeleteBinding call."* in http://es5.github.io/#x10.2.1.1.2. So it seems you can only delete bindings inside `eval` code. For whatever reasons :) – Felix Kling Aug 28 '14 at 16:52
  • @FelixKling, and only if the `eval` operator appears lexically in a non-strict environment. – Mike Samuel Aug 28 '14 at 16:53
2

You can't use delete in this way. delete is for removing properties from objects.

You can do what you want by using splice.

var myArr = [{test: 1},{test2: 2}];
console.log("before", myArr);
for (var i = 0, l = myArr.length; i < l; i++) {
  myArr.splice(i, 1);
  i--; l--;
}
console.log("after", myArr);

DEMO

Andy
  • 61,948
  • 13
  • 68
  • 95
0

Delete does delete the property and for an array the property is its value. It works in this case. Array is a special type of object which has one more property called length. Array.length doesn't update unless you use splice or any array specific methods which modifies the value..

UPDATE: You could use the following to delete the value but array length will remain the same

var myArr = [{test: 1},{test2: 2}];
console.log("before", myArr);
myArr.forEach(function(obj) {
   delete myArr[myArr.indexOf(obj)];
});

console.log("after", myArr);

ALTERNATE:

var myArr = [{a:1},{a:2},{a:1}];
for(var i=0;i<myArr.length;i++){
  delete myArr[i];
}

console.log(myArr[1]); //undefined
Liam
  • 2,837
  • 23
  • 36
  • Try `console.log(myArr.length);`. Using `delete` on an array doesn't usually produce the outcome you expect. – Felix Kling Aug 28 '14 at 16:43
  • yea but that doesn't mean its not deleting the property value. Its just not releasing the memory – Liam Aug 28 '14 at 16:44
  • Oh no, it does both, but since it's a lower level operation, the array gets into a weird state. It doesn't change the size of the array. So if you have `var arr = [1,2,3];`, and do `delete arr[1];`, you end up with `[1,,3]`, not `[1,3]`. I'm just saying, while it removes the *property* it doesn't remove the *element* (from a higher level POV). – Felix Kling Aug 28 '14 at 16:46
  • right and it doesn't update the length property of Array either – Liam Aug 28 '14 at 16:48
0

@Andy's right, you want to use splice and not delete but a little trimmer version would simply be this:

var myArr = [{test: 1},{test2: 2}];
console.log("before", myArr);
for (var i = myArr.length; i > 0; i--) {
   myArr.splice(i--, myArr[i]);
}
console.log("after", myArr);
Charles Harris
  • 304
  • 1
  • 2
  • 18