Moshe Shmukler Moshe Shmukler - 5 months ago 12
Javascript Question

confusion with hasOwnProperty

I wrote the below code, and some more, to quickly build a prototype for a 3 screen web application. Not planning to use it for production. The project is almost finished, but there is one issue that is perplexing me. I get an error -

Cannot read property 'first_name' of undefined
, even though there is a check first whether the object has the property reported as undefined. Realize the code is not an example of how such things should be handled, but why does it not work? To prevent context funkiness, I even clone the array - probably unnecessary. What is causes the undefined error?

$.ajax({
url: '/api/v1/departures/' + routeID + '/',
method: 'GET',
headers: {
'Authorization': 'Token '+ owner_token]
},
contentType:'application/json',
success: function(departures) {
console.log('departures: ' + JSON.stringify(departures));
if ( departures && ( 0 < departures.length)) {
var template = '';
for ( var j = 0; j < departures.length; j++) {
if (departures[j].route == routeID) {
var seats = (departures[j].seats).slice(0);
for ( var i = 0; i < seats.length; i++) {
template += '<div class="right-seat" data-id="' + seats[i].seat + '">' +
'<div class="right-seat-place">SEAT ' + seats[i].seat + '</div>' +
'<div class="right-seat-name">' +
seats[i].hasOwnProperty('passenger') ? seats[i].passenger.first_name + ' ' + seats[i].passenger.last_name : '' +
'</div>' +
'<div class="right-seat-reserved"><i class="glyphicon glyphicon-check"></i>&nbsp;' +
seats[i].hasOwnProperty('passenger') ? 'Reserved' : 'Available' +
'</div>' +
'</div>';
}
}
}
$('div.right-top-controls').after(template);
}
},
error: function() {
alert('error!');
}
});


Please advise.

Thank you.

Answer

hasOwnProperty just checks if an object has a property by that name. It doesn't check what that value is. That value could be undefined.

// Doesn't have the property and accessing it returns undefined
var A = {};
console.log(A.hasOwnProperty('prop'));
console.log(A.prop);


// Has the property and the value is not undefined
var B = {
  prop: 1
};
console.log(B.hasOwnProperty('prop'));
console.log(B.prop);

// Has the property AND it's value is undefined
var C = {
  prop: undefined
};
console.log(C.hasOwnProperty('prop'));
console.log(C.prop);

This means that seats[i] may very well have a passenger property but it's value could still be undefined.

There's also the problem that you're using a ternary operation during string concatenation. Essentially, + has higher precedence than ?: which results in the concatenation occurring before the conditional is evaluated. To fix this, wrap your ternaries in parentheses.

template  += '<div class="right-seat" data-id="' + seats[i].seat + '">' +
               '<div class="right-seat-place">SEAT ' + seats[i].seat + '</div>' +
               '<div class="right-seat-name">' +
                 (seats[i].hasOwnProperty('passenger') ? seats[i].passenger.first_name + ' ' + seats[i].passenger.last_name : '') +
               '</div>' +
               '<div class="right-seat-reserved"><i class="glyphicon glyphicon-check"></i>&nbsp;' +
                 (seats[i].hasOwnProperty('passenger') ? 'Reserved' : 'Available')  +
               '</div>' +
             '</div>';
Comments