Last Updated: February 25, 2016
·
419
· rabidaudio

Validating existence of object elements

I got tried of writing stuff like

if( app.user == undefined || app.user.address == undefined || app.user.address.zip == undefined){
   ...
}

So I made a little function to test existence of elements in objects. Originally, I bound it on Object.prototype but I found out the hard way that this is a problem (and later why it's a problem). Instead, it uses a trick from sugar.js to make the function non-enumerable so it doesn't break key-value loops. This means that you have to check if it has already been defined first, because you can't overwrite it once it has been set.

if(Object.prototype.hasProp === undefined){
    Object.defineProperty(Object.prototype, 'hasProp', {
    value: function() {
        var args = Array.prototype.slice.call(arguments);
        for( var i=args.length; i-->0; ){
            if( typeof args[i] !== "string" ){
                throw new TypeError(typeof args[i] + " given in place of string");
            }
            var period = args[i].indexOf('.');
            if(period>-1){
               if(!this[args[i].substr(0, period)].hasProp(args[i].substr(period+1))){
                   return false;
               }else{
                   continue;
               }
            }
            if(this[args[i]]==undefined){
              return false;
            }
        }
        return true;
    },
    enumerable: false
    });
}

That means you can do this:

d={a: "bark", b: 0, c: undefined, d: [], e: { a: { b: '1' } }, f: ""};

    d.hasProp('a', 'b');             # true
    d.hasProp('c');                  # false
    d.hasProp('e.a');                # true
    d.hasProp('e.b');                # false
    d.hasProp('e.a.b');              # true
    d.hasProp('e.a.c');              # false
    d.hasProp('d', 'f');             # true
    d.hasProp('a.b');                # false

Note that this is different from hasOwnProperty, since hasOwnProperty is unsafe (can be overwritten) and d.hasOwnProperty('c') === true since d.c exists even though it is undefined.
The original situation is now if( !app.hasProp('user.address.zip')) does the trick. Note: Doesn't work on IE<=8. Should be safe everywhere else.

Minified

void 0===Object.prototype.hasProp&&Object.defineProperty(Object.prototype,"hasProp",{value:function(){for(var a=Array.prototype.slice.call(arguments),b=a.length;0<b--;){if("string"!==typeof a[b])throw new TypeError(typeof a[b]+" given in place of string");var c=a[b].indexOf(".");if(-1<c)if(this[a[b].substr(0,c)].a(a[b].substr(c+1)))continue;else return!1;if(void 0==this[a[b]])return!1}return!0},enumerable:!1});