25

I have the following JSON response from a ajax-request.

var json = {
    "response": {
        "freeOfChargeProduct": {  
        "description": "Product",  
        "orderQty": 5,
        "productName": "XYZ",
        "qty": 6,
        "details": {
            "price": 55.5, 
            "instock": "true",
            "focQuantity": 1
        }
    }, 
    "orderLineId": 4788,
    "totalOrderLinePrice": "741.36",
    "totalOrderPrice": "1,314.92",
    "totalQty": 17
};

The JSON dosen't always return a "freeOfChargeProduct" property. So if I want to get the "freeOfChargeProduct" price, then I have to do the following:

var getFreeOfChargeProductPrice = function() { 
   var r = json.response;
   if (r && r.freeOfChargeProduct && r.freeOfChargeProduct.details) {
      return r.freeOfChargeProduct.details.price;         
   }
   return null;
};

No problems. But it's very annoying to check every property in the object, so I created a function that check if a property in a object is defined.

var getValue = function (str, context) {
    var scope = context || window,
        properties = str.split('.'), i;
    for(i = 0; i < properties.length; i++) {
      if (!scope[properties[i]]) {                       
         return null;
      } 
      scope = scope[properties[i]];        
    }
    return scope;
};

var price = getValue('json.response.freeOfChargeProduct.details.price');
// Price is null if no such object exists.

Now to my question: Is this a good or bad way to check if a property exists in an object? Any better suggestions/methods?

EDIT:

I don't wan't to use the &&-operator. I am lazy and I'm looking for a reusable method to check if a object (or property of a object) is defined.

:) Thanks!

vqdave
  • 2,361
  • 1
  • 18
  • 36
nekman
  • 1,919
  • 2
  • 15
  • 26
  • 1
    I had [a similar question](http://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key) a while back. You may be interested in some of the responses. – user113716 Oct 17 '10 at 18:32
  • Thank you for your answer! I found an answer (posted by kennebec) and gave it +1 :) – nekman Oct 17 '10 at 18:42

4 Answers4

24

Use the guard pattern:

if (json.response && json.response.freeOfChargeProduct && json.response.freeOfChargeProduct.details) {
    // you can safely access the price
}  

This is how the guard pattern works.

if (a && a.b && a.b.c) { ... } else { ... }

The first check is "Does the property a exist?". If not, the else-branch gets executed. If yes, then the next check occurs, which is "Does object a contain the property b?". If no, the else-branch executes. If yes, the final check occurs: "Does the object a.b contain the property c?". If no, the else-branch executes. If yes (and only then), the if-branch executes.

Update: Why is it called "guard pattern"?

var value = a && b;  

In this example, the member b (the right operand) is guarded by the && operator. Only if the member a (the left operand) is truthy ("worthy"), only then the member b is returned. If, however, the member a is falsy ("not worthy"), then it itself is returned.

BTW, members are falsy if they return these values: null, undefined, 0, "", false, NaN. Members are truthy in all other cases.

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • 10
    You call it guard? I call it logical AND.... never heard of *guard operator* before but maybe someone can point me to a source? – Felix Kling Oct 17 '10 at 18:42
  • Yes, I can use the &&-operator. But I want to use a common solution that I can re-use for any object. – nekman Oct 17 '10 at 18:45
  • Guard is his nickname. (Because it guards the second operand: if the first operand is falsy, it returns the first operand. If the first operand is truthy, it returns the second operand.) – Šime Vidas Oct 17 '10 at 18:45
  • @Felix The source is Douglas Crockford from Yahoo. I got this nickname from him. http://javascript.crockford.com/survey.html – Šime Vidas Oct 17 '10 at 18:47
  • 3
    Mmh, I would be careful with these kind of nicknames. Your explanation might "work" in JavaScript, but not in e.g. PHP. I would say it can *act like a guard*... Anyway, this might be splitting hairs, so nevermind! Thanks for the link! – Felix Kling Oct 17 '10 at 18:52
  • @Felix Well, JavaScript is my one and only programming language. So, for me && is the guard operator. I don't know (and don't care) how it works in other programming languages. – Šime Vidas Oct 17 '10 at 19:01
  • 3
    Crockford also tells in his book don't use them in this fashion, and adds that usage of `typeof` together with those `&&`'s is really important in that kind of situations. see. **JS: The Good Parts**. – KakambaWeb Oct 17 '10 at 23:54
  • @KakambaWeb Can you point me to the part of the book where that is discussed? In chapter 3.2 the usage of the && operator is mentioned, but not the typeof operator... – Šime Vidas Oct 18 '10 at 10:44
  • Just call it a "guard" pattern. The language defines the logical AND operator. – Jon Onstott Aug 09 '11 at 19:34
  • 5
    FYI: this is not a "guard/pattern" and not just a normal behaviour of AND operator. This behaviour of logical operators (AND, OR, ...) is called **shortcut evaluation** and it has its roots far away in C/C++ and a bit before. Not every language behaves that way - for example the VisualBasic (I hate it) does not shortcut: a && a.b && a.b.c would throw if 'a' is null, because VB evaluates all subexpressions and only then performs a logical AND... – quetzalcoatl Sep 13 '12 at 13:43
  • @quetzalcoatl The `&&` operator is the logical AND operator. However, it *can* be called "guard". It's an informal name. If I decided to use that name, I could do it. From Crockford: *"The && operator is commonly called logical and. It can also be called guard."* I don't understand what you point is. – Šime Vidas Sep 13 '12 at 14:12
  • By using "short-circuit evaluation" (sorry for the typo) keywords everything is made universally clear, or clear to people with basic IT knowledge, or at least made googlable - while using "pattern" word would rather point the poor souls at _design patterns_, where there's no such thing. Of course anyone is free to call in any anyway they like, but I find it hardly useful in terms of communication: the core terms should be shared and reused, not defined out of thin air at each year of students, each school or country. btw, a link: http://en.wikipedia.org/wiki/Short-circuit_evaluation – quetzalcoatl Sep 13 '12 at 14:30
  • @quetzalcoatl The code `if ( a && a.b && a.b.c ) { ... }` is a legitimate pattern. In my answer I used the term "guard pattern" to address it, not the `&&` operator itself. Since this pattern does *not* yet have a name, I don't see why I couldn't use the the name "guard pattern" if I thought it's appropriate. It would not be the first time that an individual introduced an informal name for a pattern, which then spread throughout the community. Example IIFE for `function () { ... }()`. – Šime Vidas Sep 13 '12 at 14:46
  • I know very well what you meant.I am just trying to show you that without those two/three words what you wrote is incomplete,and that with using it you could vastly shorten it and make more beneficial than with inventing your descriptive terms that could actually as likely turn out to be clear only to you.. Everyone would like to coin up a term used by thousands. Why not just use terms that exist for 2+ decades? That concrete has its name: it is "shortcircuit evaluation". While the term is wider than that (->wiki), it also names the pattern `a&&a.b()` Cx/Java, `do()||die()` in PHP/Ruby etc – quetzalcoatl Sep 13 '12 at 19:53
  • I do not meant to critique your answer. It is completely valid. I started with "FYI" to mark an addition to people interested in the subject. I believe they will benefit in hearing that "mine" name and that the word "pattern" is in IT world more connected to "design patterns". That's all, that's my point. Nothing more. – quetzalcoatl Sep 13 '12 at 19:55
21
if(x && typeof x.y != 'undefined') {
    ...
}

// or better
function isDefined(x) {
    var undefined;
    return x !== undefined;
}

if(x && isDefined(x.y)) {
    ...
}

This will work for any data type in JavaScript, even a number that is zero. If you are checking for an object or string, just use x && x.y within the if statement, or if you already know that x is an object, if(x.y) ...

PleaseStand
  • 31,641
  • 6
  • 68
  • 95
0

You could do something like this:

try{
    var focp = json.response.freeOfChargeProduct
    var text = "You get " + focp.qty + " of " +
        focp.productName +
        " for only $" + (focp.qty-focp.details.focQuantity)*focp.details.price +
        ", You save $" + focp.details.focQuantity*focp.details.price;
    $("order_info").innerText = text;
} catch(e) {
    // woops, handle error...
}

It would generate a message like this from the provided data in your question if the fields exists:

You get 6 of XYZ for only $277,5, You save $55.5

If the data is non-existing, you'll end up in the catch block. You could always just to a Try, Catch, Forget here if you can't come up with a way to handle the error (Maybe do a new AJAX request for the data?).

Frank
  • 2,640
  • 2
  • 21
  • 21
-2

This is not a syntax issue as it is a design pattern issue.

Question A. * Do you have control of the json server?

If the answer to this is no, which I assume, the situation will be all on the client.

Please read this: http://martinfowler.com/eaaDev/PresentationModel.html

As the server is the source, in this case it will provide the model. This pattern specifies an additional artifact: The presentation model (PM). In javascript i would suggest two artifacts, a additional for the convertor code.

According to this design pattern the PM is responsible for converting the model to the PM, and back again if necessary. In your case no conversion from PM to M will ever occur.

This means that a js object has a method or constructor that digest the model and translate itself, with the help of the convertor (below).

Doing this you will end up with a PM looking like this:

var OrderlinePM = {
    "hasFreeOfCharge": false | true,
    "freeOfCharge" : {...}

    `enter code here`

    this.getFreeOfCharge = function() {
        ...
    }

    this.fromModel = function(jsonEntry, convertor) {
        //convert this with the convertor ;) to a for this specific view usable OrderlinePM
       // also inwith 
       ...
    }

    enter code here
    "orderLineId":0, 
    "totalOrderLinePrice":"741.36", 
    "totalOrderPrice":"1,314.92", 
    "totalQty":17
};

function mySpecialFunctionPMConvertor {
    this.fromModel = function() {
        ... //do strange stuff with the model and poulate a PM with it.
    }
}

Ok, I give up trying to format code in this rich text editor :(

  • You can have several PM:s for diffrent tasks all depending on the same model object.
  • In addition this will make the converter object testable in something that could be automatically executed.... err ok maby manually, but anyway.

So the problem of the cumbersome reflection code is really not a problem. But cohesion is a issue, expessially in JavaScript.

coderdark
  • 1,481
  • 14
  • 30
Demas Sinner
  • 101
  • 2
  • 10
  • First thanks for taking the time to answer. I believe the question was expecting an answer on best practices for checking if a property exists or not in an object. Your answer although in depth, does not answer the question and does not provide a best practice on how to check an object and see if a specific property exists. – coderdark Dec 12 '19 at 01:43