Zach Coursey
Zach Coursey

Reputation: 23

Returning Value When Object Property Doesn't Exist

Running a test on my code. It should return 0 if the property passed into the function does not exist. But its not returning anything. Did I make a typo?

var obj = {
  key: [1, 2, 3]
};

function getAverageOfElementsAtProperty(obj, key) {
  if (obj[key].length === 0 || Array.isArray(obj[key]) === false || obj.hasOwnProperty(key) === false) {
    return 0;
  }
  var average = 0;
  for (var i = 0; i < obj[key].length; i++) {
    average += obj[key][i];
  }
  average /= obj[key].length;
  return average;
}

console.log(getAverageOfElementsAtProperty(obj, 'notKey'));

Upvotes: 0

Views: 2007

Answers (2)

Scott Marcus
Scott Marcus

Reputation: 65806

If you don't pass an array to your function, it fails when it tries to get the length of the object that was passed, so that shouldn't be how you test initially. You just need to see if the property exists and that is done by simply attempting to access the property in an if condition.

Now, if you are going to add tests to see if the property does exist and that it is an array, then you have to add more tests to check the items in the array to see if they are numbers, otherwise trying to get a numerical average will fail.

Since there are really two things to do (check if the property is there and get math average), I would break this into two functions:

var obj1 = {
  key: [1, 2, 3]
};

var obj2 = {
  key: [1, "test", 3]
};

function getAverageOfElementsAtProperty(obj, key) {
  if (obj[key] && Array.isArray(obj[key])) { 
    // Ok, we have the right property and there is an array there,
    // now we have to test that each item in the array is a number
    var numbers = obj[key].every(function (currentValue) {
      return typeof currentValue === "number";
    });
    
    // Return the average if we have all numbers or 0 if not
    return numbers ? getAverage(obj[key]) : 0;
  } else {
    return 0;
  }
}

function getAverage(arr){
  var average = 0;
  // Array.forEach() is much simpler than counting loops
  arr.forEach(function(item) {
    average += item;
  });
  return average / arr.length;
}

console.log(getAverageOfElementsAtProperty(obj1, 'notkey'));  // 0
console.log(getAverageOfElementsAtProperty(obj1, 'key'));     // 2
console.log(getAverageOfElementsAtProperty(obj2, 'key'));     // 0 - obj2 does not contain all numbers

Upvotes: 3

S&#248;lve
S&#248;lve

Reputation: 4406

Since obj['notKey'] does not exist, it does not return an array. Therefore you cannot do .length of undefined. I would change it to typeof to see if its defined or not.

var obj = {
  key: [1, 2, 3]
};

function getAverageOfElementsAtProperty(obj, key) {

  if (typeof obj[key] == 'undefined' || Array.isArray(obj[key]) === false || obj.hasOwnProperty(key) === false) {
    return 0;
  }

  var average = 0;
  for (var i = 0; i < obj[key].length; i++) {
    average += obj[key][i];
  }
  average /= obj[key].length;
  return average;
}

console.log(getAverageOfElementsAtProperty(obj, 'notKey'));

Upvotes: 1

Related Questions