Javascript Style Tip: Use “in” and “delete”

Javascript provides two very handy operators, in and delete.

Consider this code fragment:

var obj = {
 foo : 'quux',
 bar : 'baz',
 doSomething : function () {
  // do something...
 }
};

So, we’ve created an object, and then some other things happen. Later in the code, we want to remove the “foo” property, so we do this:

obj.foo = undefined;

Still later, we only want to do something if the foo property has not been unset, so we check it:

if ( obj.foo !== undefined ) {
 // do something
}

That works, and it’s fairly common, but it’s klunky, and not as readable as this:

delete obj.foo;

if ( 'foo' in obj ) {
 // do something
}

The first one says, Delete “foo” from the object. The second asks, Is “foo” in the object? The difference between the first and second approaches is that the second uses intuitive wording in the code.

Note: You must use delete if you want to use in. Setting something to undefined manually will not cause it to return false when testing whether the property is in the object.

As an added bonus, using the delete operator also removes the property from the for/in iteration loop, since it actually removes it from the object’s key list rather than simply setting it’s value to undefined.

var obj = {asdf:'foo',bar:'baz'};
obj.asdf = undefined;
for ( var i in obj ) {
 console.log(i,obj[i]);
}
// outputs:
// asdf undefined
// bar baz

var obj = {asdf:'foo',bar:'baz'};
delete obj.asdf;
for ( var i in obj ) {
 console.log(i,obj[i]);
}
// outputs:
// bar baz

Note: you’ll need to wrap the “in” statement in parentheses if you want to negate it. For example, this is a bug:

var obj = { asdf:'foo',bar:'baz' };
var f = 'quux';
if ( !f in obj ) {
 alert( 'not there!' );
}

The alert will never fire. Can you figure out what’s happening? Here’s a clue:

var obj = { 'false':1, asdf:'foo', bar:'baz' };
var f = 'quux';
if ( !f in obj ) {
 alert( 'not there!' );
}

Now the alert will fire. What’s up?

The order of operations is this:

  1. Process the !f, which converts ‘quux’ to a boolean (true), and then gets the opposite (false).
  2. The “in” operator converts the value back to a string, and false.toString() is the string ‘false’.
  3. Since ‘false’ is not a key in the object, the “in” operator returns false, and the conditional fails.

In the second case, since the string ‘false’ is a key in the object, the “in” operator returns true, and the conditional fires. Of course, using “false” as a key in an object is a really stupid thing to do, but if some bunk data comes into your program somehow, it can happen. Always wrap your “in” clauses in parentheses, and you’ll never have a problem. In this case, it works as expected:

var obj = { asdf:'foo', bar:'baz' };
var f = 'quux';
if ( !(f in obj) ) {
 alert( 'not there!' );
}

Update

I’m finding that a lot of people are hitting this page with search queries that seem to indicate they’re looking to remove a style property from a Dom node. delete won’t help you much there, since the style property is a get-and-set-only property. (IE, you can read from and write to it, but you can’t delete from it.)

Most of the time, you shouldn’t be messing with the style property directly in Javascript, anyhow. Instead, add and remove semantically meaningful class names, and put the style information related to those states in the CSS. Of course that’s not always an option, I know. So, you can remove the inline setting by simply setting it to an empty string, like this:

document.body.style.background="red"; // turns the page red.
document.body.style.background=""; // turns the page back to whatever it was.

Cheers!

4 Comments

  1. Nicholas Zakas

    Posted Tue 2007-09-11 @ 18:27:43 | Permalink| Reply

    To be a bit more complete, delete removes instance properties/methods; if a property of the same name exists on the prototype then it will show up using “in”. For example:

    function MyType (){
      this.color = "red";
    }
    MyType.prototype.color = "blue";
    var o = new MyType();
    alert("color" in o);
    alert(o.color); //red
    delete o.color;
    alert("color" in o);
    alert(o.color); //blue

    In this case, the “color” property is never truly removed from the object because it searches up to the prototype for its definition.

  2. Isaac

    Posted Wed 2007-09-12 @ 11:08:09 | Permalink| Reply

    Thanks for pointing that out. in searches up the prototype chain, but delete only deletes it off of the specific object supplied. All the more reason why excessive use of classic inheritance paradigms in a prototypal language can get confusing.

    In your example above, this would get rid of the “color” member from o:

    delete o.constructor.prototype.color;

    Of course, it would also delete it from all objects derived from the MyType constructor.

    To get around this problem, you can use the hasOwnProperty method instead. While I prefer in for its intuitiveness and brevity, hasOwnProperty is sometimes more appropriate when dealing with prototype chains. Ultimately, it’s up to the programmer to understand the difference and to use them appropriately and clearly.

  3. Matt B

    Posted Sun 2008-01-20 @ 09:24:19 | Permalink| Reply

    Interestingly, in IE 6 / 7, some very odd side effects can sometimes been seen when using the

    document.body.style.background=""

    syntax to remove styling.

    When working with form fields:

    Apply no styling to the input element, and IE will put it’s default borders around it.

    document.getElementById('test').style.border = '#FF0000';

    You’ll get red borders around your form field.

    document.getElementById('test').style.border = '';

    I’m guessing IE interprets this as “border:none,” because the form field’s border disappears entirely, rather than going back to the default.

    However, it work fine in Mozilla. All the usual fun off the fair, then…

  4. Isaac

    Posted Sun 2008-01-20 @ 19:53:19 | Permalink| Reply

    @Matt B

    Interesting, I never noticed that.

    This is just another reason why Javascript should really not touch the style object directly, and should instead change the className property and let the CSS rules live in a style sheet.

Post a Comment

Post Friendly. About