开发者

Check if a object is defined, best practice.

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.f开发者_高级运维reeOfChargeProduct.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!


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.


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) ...


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?).


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜