hasOwnProperty with more than one property
Asked Answered
C

6

8

I'm trying to discover if an object has some properties and I'm having trouble using the hasOwnProperty method.

I'm using the method on an array (I know the documentation states a string).

The following line returns true:

{ "a": 1, "b": 2 }.hasOwnProperty( ["a"]);

This line returns also true:

{ "a": 1, "b": 2 }.hasOwnProperty( "a", "b");

But this one returns false:

{ "a": 1, "b": 2 }.hasOwnProperty( ["a", "b"])

And I need it to return true. I'm using Object.keys(object) to get the properties that I'm using, and it returns me an array, so I need to use an array on hasOWnProperty.

Is there some theoric concept I'm missing? And is there some way to fix this problems?

Cat answered 6/2, 2018 at 23:19 Comment(0)
G
20

There are two things going on here.

First, hasOwnProperty only takes one argument. So it'll ignore whatever other arguments you pass to it.

Second, (and I'm simplifying slightly here) it's going to convert that first argument to a String, and then check to see if the object has that property.

So let's look at your test cases:

The reason { "a": 1, "b": 2 }.hasOwnProperty( "a", "b"); returns true is because it's ignoring the second argument. So really it's just checking for "a".

{ "a": 1, "b": 2 }.hasOwnProperty( ["a", "b"]) returns false because the first argument, ["a", "b"], gets converted to "a,b", and there's no { "a": 1, "b": 2 }["a,b"].

To find out if a given object has all the properties in an array, you can loop over the array and check each property, like so:

function hasAllProperties(obj, props) {
    for (var i = 0; i < props.length; i++) {
        if (!obj.hasOwnProperty(props[i]))
            return false;
    }
    return true;
}

Or, if you're feeling fancy, you can use the every function to do this implicitly:

var props = ["a", "b"];
var obj = { "a": 1, "b": 2 };
var hasAll = props.every(prop => obj.hasOwnProperty(prop));

I hope that helps clarify things. Good luck!

Gangland answered 6/2, 2018 at 23:40 Comment(0)
S
2

If you want to check the object's own properties, you could use the Object.getOwnPropertyNames method. It returns an array of all properties (including non-enumerable properties except for those which use Symbol) found directly upon a given object.

let o = { "a": 1, "b": 2 };
Object.getOwnPropertyNames(o).forEach(k => console.log(`key: ${k}, value: ${o[k]}`));
Schizoid answered 6/2, 2018 at 23:34 Comment(0)
O
2

Given the documentation, it seems that the hasOwnProperty() method takes either a string or a symbol as an argument. So I think hasOwnProperty() isn't capable of taking a collection of strings and testing if the object has each one as a property.

I think another approach would be to take the array of strings and iterate through each one. Then for each string in your array (the properties you want to test for), you could test if the object has that property. Here's an example:

const o = new Object();
var propsToTest = ['a', 'b'];
o.a = 42;
o.b = 40;

var hasProperties = true;
propsToTest.forEach(function(element) {	// For each "property" in propsToTest, verify that o hasOwnProperty
  if(!o.hasOwnProperty(element))
    hasProperties = false;
});

console.log(hasProperties);
Osana answered 6/2, 2018 at 23:39 Comment(0)
R
2

So this is an old question and I'm kinda surprised no one else has thought to write it but this is usually solved using .every on the array. So for the original question, the code should be something like:

["a", "b"].every((item) => ({ "a": 1, "b": 2 }.hasOwnProperty(item)))

This will return a simple true. Array .every will run a condition for every item in an array and only return true if the condition is true for all item. See the the mozilla web docs

Rheometer answered 21/12, 2021 at 13:53 Comment(1)
Writing it in a more reusable format would be more helpful, as in create a small arrow function or standard function to take in the parameters. Also the way this is written, you are actually testing the properties on a new object every time that function the every function is invoked and while it works, it is misleading and ideally you want to test the set of properties of a single object.Fisticuffs
C
1

First, in terms of getting your third snippet to return true, I don't think that's possible. The best you could do would be to check each property individually:

const obj = { "a": 1, "b": 2 };
console.log(["a", "b"].every(p => obj.hasOwnProperty(p)))

Which should give you what you want.


But to understand why the first two returned true, but the third false:

The hasOwnProperty method only accepts a single argument (additional arguments are ignored), and it expects that argument to be a string. If the argument is not a string, then JavaScript will attempt to coerce it to one (usually by using a .toString method).

So your first two snippets are equivalent because:

["a"].toString() === "a", so hasOwnProperty(["a"]) is the same as hasOwnProperty("a") after the argument is converted to a string.

Then in your second snippet, the second argument "b" is simply ignored, leaving it equivalent to just hasOwnProperty("a") again.

And finally, your third snippet uses ["a", "b"], and ["a", "b"].toString() === "a,b", which is not a property of your object.

Catlee answered 6/2, 2018 at 23:38 Comment(0)
T
0

You can achieve this with a for...in loop like this

const obj = { "a": 1, "b": 2 };

for (key in obj) {
        if (obj.hasOwnProperty(key)) {
           console.log('has', key, obj[key]);
        } else {
           console.log('not', key, obj[key]);
        }
}
Tetralogy answered 6/2, 2018 at 23:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.