skip to Main Content

This is my Object

var MyObject =[{
  first: "Romeo",
  last: "Montague"
}, {
  first: "Mercutio",
  last: null
}];

And this is target property:

var Target = {
  last: "Capulet"
};

I want to find out all Object have the target property or not. And from my object and target property above expected result is True because both of them have ‘last’ property

Function to find object:

function Find(obj,source){
  const key = Object.keys(source);

  console.log(obj.every(keys => obj.hasOwnProperty(key))); /* false*/
  console.log(obj[0].hasOwnProperty(key));/*true*/
  console.log(obj[1].hasOwnProperty(key));/*true*/
}

I don’t understand why console.log(obj.every(keys => obj.hasOwnProperty(key))); returns false but console.log(obj[0].hasOwnProperty(key)) and console.log(obj[1].hasOwnProperty(key)) return true.

3

Answers


  1. Split your problem into smaller, composable, parts:

    1. given a property and its value, check if an object has that property, or even has that property with that exact value.
    2. given that functionality, check a list of objects all in the same way
    3. given that functionality, check a list of objects for any number of key/value properties.

    The first is easy enough:

    function checkEntry(entry, propName, value) {
      const found = entry[propName];
      return found !== undefined && found !== null;
      /*
        or "return !!found" if "falsey" values like 0 or "" should be false, too,
        or even "return found && found === value" if we need strict value agreement,
        or use entry.hasOwnProperty here, but you're not showing a prototyped object,
        so there's not much point in getting that low-level.
      */
    }
    

    The second is then just a matter of wrapping that in an every for our data list:

    function checkList(dataList, propName, value) {
      return dataList.every((entry) => checkEntry(entry, propName, value));
    }
    

    And the third is then just a matter of wrapping that in another every for our required properties:

    function checkListForRequirements(datalist, requiredProperties) {
      return Object.entries(requiredProperties).every(([propName, value]) =>
        checkList(datalist, propName, value)
      );
    }
    

    Now that we know the composition, we can put it all together into a single function and run it on our data:

    function checkListForRequirements(dataList, requiredProperties) {
      return Object.entries(requiredProperties).every(([propName, value]) =>
        dataList.every((entry) => entry[propName] ?? false)
      );
    }
    
    const data = [
      {
        first: "Romeo",
        last: "Montague",
      },
      {
        first: "Mercutio",
        last: null,
      },
    ];
    
    const requiredProperties = {
      last: "Capulet",
    };
    
    console.log(checkListForRequirements(data, requiredProperties)); 
    
    const moreData = [
      {
        first: "Romeo",
        last: "Montague",
      },
      {
        first: "Mercutio",
        last: "Capulet",
      },
    ];
    
    console.log(checkListForRequirements(moreData, requiredProperties));
    Login or Signup to reply.
  2. You have a typo here:

    function Find(obj,source){
      const key = Object.keys(source);
    
      console.log(obj.every(keys => obj.hasOwnProperty(key)));
    //                      ^^^^    ^^^
      console.log(obj[0].hasOwnProperty(key));/*true*/
      console.log(obj[1].hasOwnProperty(key));/*true*/
    }
    

    Your every callback is declaring a parameter named keys, which you are not using, instead you call hasOwnProperty on the obj array again (which indeed does not have the key property).

    Name your variables properly, using plural for things that are arrays, and use only the first of the Object.keys(…) as the key (you were using a single-element array, which was weird but worked because it was coerced to a string). Corrected:

    function find(objects, source) {
      const key = Object.keys(source)[0];
    //                               ^^^
      return objects.every(obj => Object.hasOwn(obj, key));
    }
    
    Login or Signup to reply.
  3. Your code has some flaws:

    const key = Object.keys(source);
    console.log(obj.every(keys => obj.hasOwnProperty(key)));
    
    1. key is an array of property names not a property name, use const [key] = Object.keys(source);
    2. obj.hasOwnProperty refers to MyObject array, it should be keys. But keys argument name is misleading, use something like item:
    console.log(obj.every(item=> item.hasOwnProperty(key)));
    

    The solutions:

    Here is a generic solution for any number of properties in Target. We use the second Array::every() here to ensure that every property in Target is MyObject‘s item:

    const keys = Object.keys(Target);
    const result = MyObject.every((item, count) => keys.every(key => key in item));
    console.log(result);
    <script>
    var MyObject =[{
      first: "Romeo",
      last: "Montague"
    }, {
      first: "Mercutio",
      last: null
    }];
    var Target = {
      last: "Capulet",
      first: "TEST"
    };
    </script>

    For only the first property I would use in operator since it seems the fastest:

    const [key] = Object.keys(Target);
    const result = MyObject.every(obj => key in obj);
    console.log(result);
    <script>
    var MyObject =[{
      first: "Romeo",
      last: "Montague"
    }, {
      first: "Mercutio",
      last: null
    }];
    var Target = {
      last: "Capulet"
    };
    </script>

    And a benchmark:

    Cycles: 1000
    -------------------------------------------------------------
    Alexander one property   :  100(min)  117  133  130  100  101
    Alexander all properties :  113(min)  113  140  144  113  144
    Pomax                    :  166(min)  166  200  174  176  182
    -------------------------------------------------------------
    https://github.com/silentmantra/benchmark
    
    <script benchmark="1000">
    
        const chunk = [{
          first: "Romeo",
          second: "Dummy",
          third: "Dummy",
          fourth: "Dummy",
          last: "Montague",
        }, {
          first: "Mercutio",
          second: "Dummy",
          third: "Dummy",
          fourth: "Dummy",
          last: null
        }];
    
        const MyObject = [];
        
        let count = 10000;
        while(count--) MyObject.push(...structuredClone(chunk));
        
        var Target = {
          last: "Capulet"
        };
    
    // @benchmark Pomax
    
    function find(objects, source) {
      const key = Object.keys(source)[0];
      return objects.every(obj => Object.hasOwn(obj, key));
    }
    
    // @run
    find(MyObject, Target);
    
    // @benchmark Alexander one property
    
    const [key] = Object.keys(Target);
    MyObject.every(obj => key in obj);
    
    
    // @benchmark Alexander all properties
    
    const keys = Object.keys(Target);
    MyObject.every((item, count) => keys.every(key => key in item));
    
    </script>
    <script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search