2

Sometimes I run the following on JSON string objects:

for(var i in JSONObject){
    ....
}

Do I need to run .hasOwnProperty here? I assume since JSON isn't extended from a parent object, it is safe to assume all its properties are its own.

Lloyd Banks
  • 35,740
  • 58
  • 156
  • 248
  • 5
    I don't see any JSON here. Please read the usage description of the `json` tag. – trincot Dec 23 '16 at 17:31
  • 4
    Depends on what `JSONObject` is. Notice [there are no "JSON objects" in Javascript](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/) (except for the [`JSON` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) which you certainly don't mean). – Bergi Dec 23 '16 at 17:33
  • 1
    That depends. Do you want to protect yourself against `Object.prototype.foo = 42;` that some other code might do? If yes, then you need `hashOwnProperty`. And also already said by the others, there is no JSON here. What are "JSON string objects" ? – Felix Kling Dec 23 '16 at 17:33
  • 1
    @FelixKling If you want to protect yourself against `Object.prototype.foo = 42`, just protect your entire codebase from having such assignments. You never need to protect property enumeration. – Bergi Dec 23 '16 at 17:36
  • 2
    *"I assume since JSON isn't extended from a parent object"* `JSONObject` isn't JSON. A string containing JSON is what you passed to `JSON.parse`. It *returns* a JavaScript value (probably an object in your case). (Almost) every object "inherits" from `Object.prototype`. – Felix Kling Dec 31 '16 at 19:01
  • @Bergi: Third party libraries? :-/ – Felix Kling Dec 31 '16 at 19:02
  • Can't you just log `Object.getPrototypeOf(JSONObject)` to see whether it inherits or not? We have no way to know what that object is. – Oriol Dec 31 '16 at 19:11
  • 1
    There is no such thing as a *"JSON string object"*. What you have is a plain object, nothing more, nothing less. JSON has nothing to do with that, I'm just clarifying that. No need to "attack" me personally. If you haven't yet read the link that Bergi posted, here it is again: http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/ . It explains why it is wrong/confusing to talk about "JSON objects" in JavaScript. – Felix Kling Dec 31 '16 at 22:30
  • 1
    @FelixKling I would hope that everyone can avoid those third-party libraries that employ such worst-practises. Even if they need to extend `Object.prototype` (for backcompat or anything), they could do so [safely](http://stackoverflow.com/q/13296340/1048572). I'd wager that in general `JSONObject.hasOwnProperty(i)` (instead of the proper `hasOwnProperty.call(JSONObject, i)`) causes more harm than it avoids. – Bergi Dec 31 '16 at 23:55
  • @Bergi: I fully agree with you. I'm just talking about the general case. – Felix Kling Jan 01 '17 at 00:00
  • OK, I posted an answer, I hope it helps. I'm sorry if I did anything to offend you that you felt the need to write such comments, which I personally found insulting. Maybe it was not your intention to insult me, but you did. Take care! – Felix Kling Jan 01 '17 at 00:01

2 Answers2

3

I assume since JSON isn't extended from a parent object, it is safe to assume all its properties are its own.

That's not quite right. Unless an object was created via Object.create(null), it has Object.prototype in its prototype chain. Properties such as hasOwnProperty, that you mentioned, or toString are defined there. So, most objects have more than just "their own" properties, that includes objects that have been created from JSON via JSON.parse.
However, all standard properties defined on Object.prototype, are not enumerable and hence won't appear in a for..in loop.

So, should you use hasOwnProperty? As so often: It depends.

If you are sure that no code that you use, be it your own or third-party code, adds enumerable properties to Object.prototype, then there is no reason to use hasOwnProperty in the loop.

If you are not sure about it then you might want to use hasOwnProperty, but it would be better to simply not extend Object.prototype with enumerable properties and avoid third-party code that does.


Related:

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    There was a [brief discussion on ES Discuss](https://esdiscuss.org/topic/add-an-option-to-omit-prototype-of-objects-created-by-json-parse) about a flavor of `JSON.parse` which would create an object with no prototype, but it didn't go anywhere, and as you say, it usually doesn't matter anyway. –  Jan 05 '17 at 04:20
-2

I ran a couple of tests on this and JSON strings won't transmit inherited properties. So let's say you have an API response from an endpoint that looks like this after you prettify it:

{
    "one": "blue",
    "two": "watermellon",
    "three": "lalal",
    "four": "value"
}

If you run a for(var i in JSONObject) loop over the parsed value of the above, you'll only ever find four properties associated with the object as long as you didn't explicitly attach any properties to the parent Object literal (Object.prototype) in your current environment.

Lloyd Banks
  • 35,740
  • 58
  • 156
  • 248
  • *"you'll only ever find four properties associated with the object"* No, that's not correct. It depends on the environment where the object is used. Proof: https://jsfiddle.net/scde1pfL/ . As I have explained in my answer, `for...in` iterates over all enumerable properties. If you happen to have an enumerable property on `Object.prototype`, it will be iterated over as well. Again, the chance that this happens is not likely, but it's incorrect to say that it will *never* happen. *"I ran a couple of tests on this and JSON strings won't transmit inherited properties."* That was never questioned. – Felix Kling Jan 05 '17 at 04:25
  • *JSON strings won't transmit inherited properties* JSON strings don't transmit anything. They are just strings. If you mean "JavaScript objects created by `JSON.parse`", then please clarify that. If that is what you meant, what inherited properties did you think they might "transmit"? –  Jan 05 '17 at 05:01
  • *as long as you didn't explicitly attach any properties to the parent Object literal (`Object.prototype`)* It is not a "parent Object literal"; it is the prototype. And your statement is incorrect anyway unless you say "didn't explicitly attach any *enumerable* properties". –  Jan 05 '17 at 05:02