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 null
s.
I am looking for something like "coalesce" that:
- will know how to handle
null
s and will not throw exceptions foritem.product
ifitem
isnull
. - 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 null
s.
I am looking for something like "coalesce" that:
- will know how to handle
null
s and will not throw exceptions foritem.product
ifitem
isnull
. - 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
6 Answers
Reset to default 4You 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 null
s, 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 throw
ed. What you can do inside the catch statement is to fill your object with the default that is missing.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745102132a4611336.html
评论列表(0条)