Of two equal JSON objects, accessing values in javascript works in one case, the other returns undefined

Viewed 81

I have two identical JSON objects, such that:

JSON.stringify(obj1) == JSON.stringify(obj2); // returns true

Also if I log them in the console, I can inspect both of them properly and everything works as expected. However for some reason I cannot access the values of obj2:

console.log(obj1.type) // returns "FeatureCollection"
console.log(obj2.type) // returns undefined

The json data is loaded from file and looks like this (data.json):

{
  "type": "FeatureCollection",
  "name": "data",
  "crs": {
    "type": "name",
    "properties": {
      "name": "urn:ogc:def:crs:OGC:1.3:CRS84"}
    },
    "features": [
      {
        "type": "Feature",
        "properties": {"id": 0, "qualities": ["q1", "q2", "q3"]},
        "geometry": {"type": "Point", "coordinates": [25.227297, 36.418335]}
      }]
}

Here is the difference: This scenario is happening in a react app (in .jsx file). obj1 is loaded directly from file in the .jsx file. obj2 is passed into the react component and accessed through this.props. It was previously loaded with same syntax from same file. These are the two files:

leaflet-map.jsx:

import React from "react";
import * as geojson from "../assets/data.json";

export default class Map extends React.Component {
    render(){
        var obj1 = geojson;
        var obj2 = this.props.geojson;
        console.log(JSON.stringify(obj1) == JSON.stringify(obj2));
        console.log(obj1.type);
        console.log(obj2.type);
        return (<div></div>);
        }
}

LeafletMap.jsx

import React from "react";
import Map from "../../../components/leaflet-map";
import * as geojson from "../../../assets/data.json";

export default function LeafletMap() {
    return (<Map geojson={geojson}></Map>);
}

What is happening? This is so strange I don't even know where to start looking...

Update:

I tried @TheMaster 's hint and changed Map class definition to:

export default class Map extends React.Component {

    constructor(props){
        super(props);
        console.log(this.props.geojson);
        console.log(this.props.geojson.type);
    }
    render(){
        return (<div></div>);
    }
}

Result:

enter image description here

So appearently the constructor is called twice(?).

2 Answers

The Prototype Chain;

const p = Object.create(null);
const obj1 = Object.create(p);
p.type = "someType";
obj1.txt = "val";
const obj2 = { txt : "val" };


console.log(JSON.stringify(obj1) == JSON.stringify(obj2)); // true
console.log(obj1.type); // someType
console.log(obj2.type); // undefined

A very short explanation:

If the object doesn't contain the attribute, JavaScript will traverse up the whole prototype chain to find that attribute, and if it finds that on a parent, it will return that otherwise undefined.

Thanks to @TheMaster 's comment I now know that I can access the object with this.props.obj2.default. That solves my problem on a practical level, even though I still don't understand the behaviour. This redifinition of the Map class definition illustrates the behaviour:

import React from "react";
import Map from "../../../components/leaflet-map";
import * as obj2 from "../../../assets/data.json";

export default function HelperMap() {
  return (
      <div>
        <Map obj2={obj2}></Map>
      </div>
  );
}
import React from "react";
import * as obj1 from "../assets/data.json";

export default class Map extends React.Component {

    constructor(props){
        super(props);
        console.log(obj1);
        console.log(obj1.type);
        console.log(this.props.obj2);
        console.log(this.props.obj2.type);
        console.log(this.props.obj2.default.type);
    }
    render(){
        return (<div></div>);
        }
}

Returns:

enter image description here

Related