最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - coalesce in javascript - Stack Overflow

programmeradmin0浏览0评论

I am using jQuery, Backbone (and underscore) and RequireJS.

I have this code:

var products = _.map(items, function(item) {
    return new ProductModel({
        title: item.product.title,
        description: item.product.description,
        link: item.product.link,
        'image-src': item.product.images[0].link,
        'image-height': item.product.images[0].height,
        'image-width': item.product.images[0].width
    });
});

Unfortunately, everything might be null. By everything I mean that item, item.product, item.product.images, item.product.images[0] and so on might be nulls.

I am looking for something like "coalesce" that:

  1. will know how to handle nulls and will not throw exceptions for item.product if item is null.
  2. will allow me to provide a default value if there was a null.

Is there anything like that?

I am using jQuery, Backbone (and underscore) and RequireJS.

I have this code:

var products = _.map(items, function(item) {
    return new ProductModel({
        title: item.product.title,
        description: item.product.description,
        link: item.product.link,
        'image-src': item.product.images[0].link,
        'image-height': item.product.images[0].height,
        'image-width': item.product.images[0].width
    });
});

Unfortunately, everything might be null. By everything I mean that item, item.product, item.product.images, item.product.images[0] and so on might be nulls.

I am looking for something like "coalesce" that:

  1. will know how to handle nulls and will not throw exceptions for item.product if item is null.
  2. will allow me to provide a default value if there was a null.

Is there anything like that?

Share Improve this question edited Dec 15, 2015 at 10:42 Klors 2,6742 gold badges27 silver badges42 bronze badges asked Nov 6, 2012 at 17:48 NaorNaor 24.1k50 gold badges156 silver badges270 bronze badges 1
  • It's better to provide default values in the model... – Soroush Khosravi Commented Nov 6, 2012 at 18:09
Add a ment  | 

6 Answers 6

Reset to default 4

You can use boolean && and rely on short-circuiting:

...
'image_src': item && item.product && item.product.images && item.product.images[0] && item.product.images[0].link,
'image_height': item && item.product && item.product.images && item.product.images[0] && item.product.images[0].height,
...

More likely, you don't want to perform the same test across so many lines. I would store your return value with its various attributes set to some sane default and then conditionally add the real values if your item.product.images[0] is non-null:

var returnObject = { /* default values here */ }, product, image;

if (product = item && item.product) {
    returnObject.title = product.title,
    returnObject.description = product.description,
    returnObject.link = product.link
};

if (image = product && product.images && product.images[0]) {
    returnObject['image-src'] = image.link;
    returnObject['image-height'] = image.height;
    returnObject['image-width'] = image.width;
}

return returnObject;

I would first .filter out the empty products:

var goodItems = _.filter(items, function(item) {
     return 'product' in item;
});

and the simplify the image tests by supplying an empty object if the one in the product doesn't exist:

var products = _.map(goodItems, function(item) {
    var product = item.product;
    var img = (product.images && product.images[0]) || {};
    return new ProductModel({
        title: product.title,
        description: product.description,
        link: product.link,
        'image-src': img.link,
        'image-height': img.height,
        'image-width': img.width
    });
});

If you want a default value for nulls, then you could create a helper function like this:

var coalesce = function(obj, path, defaultValue) {
  while(obj != null && path.length) {
    obj = obj[path.shift()];
  }
  return (obj == null ? defaultValue : obj);
};

You would use it as follows:

coalesce(item, ["product", "title"], "Default title");
coalesce(item, ["product", "images", 0, "link"], "Default image link");

Not sure there is anything like that but I think you may create and use custom functions as below:

    return new ProductModel({
             title: getPorductAttribute(item,'title'),
             description: getPorductAttribute(item,'description'),
             link: getPorductAttribute(item, 'link'),
             'image-src': getImageAttirbute(item,0,'link'),
             'image-height': getImageAttirbute(item,0,'height'),
             'image-width': getImageAttirbute(item,0,'width')
            });


  function getPorductAttribute(item, attributeName){
       if(!(item && item.product)) 
           return defaultValue;
       return item.product.getAttribute(attributeName);
   }

  function getImageAttirbute(item, index, attributeName){
       if(!(item && item.product && item.product.images)) 
           return defaultValue;
       return item.product.images[index].getAttribute(attributeName);
   }

You can use the logical OR operator "||" to coalesce, as described here...

http://pietschsoft./post/2008/10/14/JavaScript-Gem-Null-Coalescing-using-the-OR-Operator

var something = maybeNothing || 0;

Works against both null or undefined.

If you are unsure what the object actually is. You can do the good old try-catch...

var testObject = {
  alpha: {
    beta: null
  },
  gama: {
    delta: null
  }  
};

try {
    console.log(testObject.alpha.beta.gama.delta);
} catch(err) {    
    alert(err.message);
}

This will not break your app, since the error is not throwed. What you can do inside the catch statement is to fill your object with the default that is missing.

发布评论

评论列表(0)

  1. 暂无评论