Javascript object both has properties and is empty

Viewed 424

I have a web application with a UIController module, which gets user input from the DOM, a CBController module, which outputs processed user input to the Clipboard, and an appController module, which processes the user input for output to the Clipboard. The appController module has an Appobj object which is scoped to the appController module and stores the state and values for each UI element. So far so good.

But here's the issue - I just wrote the Appobj object to the Firefox Developer Edition console from an appController public function and although the console lists all its properties as expected, the object evaluates to empty. That is, Object.keys returns an empty array with no length and for/in fails silently, i.e. any console actions within the for/in are ignored, and the object's properties can't be accessed, i.e. return undefined. The only difference between this Appobj object and an Appobj object that behaves normally (i.e. has length and returns a non-empty array with Object.keys) is that in the Firefox console, the 'empty' Appobj object shows no ellipses between the curly brackets while the populated Appobj object (when called from an appController private function) shows ellipses, as shown:

Empty Appobj with properties:

enter image description here

Normal Appobj:

enter image description here

Both objects appear to have identical prototypes. Object.hasOwnProperties didn't help. What's worse, in Chrome both these are identical in the console, that is, there are no ellipses to distinguish them, so if I was using Chrome I'd not been to determine any difference between them at all except that one of them is functionally empty.

I've worked around it so it's not mission-critical, but I'd be grateful if someone could help me understand this, since I did lose a couple hours on it.

Code snippet is included, but note that the SO console shows Appobj as empty while FF and Chrome show it as having properties even though it is functionally empty. As in the screenshots above, FF shows no ellipses within the curly brackets. To get the ellipses, uncomment the line as described in the code.

var MyApp = (function () {
  var UIController = (function() {
    return {
      initUI: function() {
        appController.getAppobj();
        appController.initmyAppControllerFunction();
      },
      writeCurImgToDOM: function(Appobj) {
        document.querySelector('#cur-img').style.width = Appobj.imgNW + 'px';
        document.querySelector('#cur-img').style.height = Appobj.imgNH + 'px';
      }, 
      populateAppobj: function (Appobj) {
        let curImg;
        function populateAppProperties(Appobj) {
          // !VA Get the current image
          curImg = document.querySelector('#cur-img');
          Appobj.imgNW = curImg.naturalWidth;
          Appobj.imgNH = curImg.naturalHeight;
        }
        populateAppProperties(Appobj);
      },
    };
  })();

  var appController = (function(UICtrl) {
    let Appobj = {};
    function myAppControllerFunction() {
      UIController.populateAppobj(Appobj);
      UIController.writeCurImgToDOM(Appobj);
    }
    return {
      getAppobj: function() {
        // Uncomment the line below to make Appobj a 'normal' object
        // UIController.populateAppobj(Appobj); 
        console.log('Appobj is: ');
        console.dir(Appobj);
        Object.keys(Appobj).length === 0 ? console.log('getAppobj NO LENGTH') : console.log('getAppobj HAS LENGTH');
      },
      initmyAppControllerFunction: function() {
        myAppControllerFunction(true);
      },
      // !VA appController public
      init: function(){
        console.log('App initialized.');
        // !VA Initialize the UI
        UICtrl.initUI();
      }
    };
  })(UIController);
  appController.init();
})();
body {
  background: #000000;
}
#main-image {
  position: relative;
  display: block;
}
#cur-img {
  display: block;
  margin: 0 auto;
}
<!DOCTYPE html>
<html lang="en" dir="ltr" itemscope itemtype="http://schema.org/Article">
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" media="all" href="css/scrap.css">
</head>
<body>
  <div id="main-image">
      <div id="cur-img-container">
        <img src="http://vanocular.com/public/_200X150.png" id="cur-img" alt="">
      </div>
  </div>
</body>
</html>

1 Answers

is it possible the object is getting populated after the console.log?

show your code including the console log statements.

its possible to create an empty object, then do a console.log statement, then later populate the object. when this happens, your console.log will actually show the object populated even though it was empty at the time the console.log statement ran. and if you ran any code between the console.log and when it was populated, it would show it empty. Could this be happening?

---edit---

Just did some testing with chrome:

var obj = {}
obj['field'] = 'test';
console.log(obj);

console looks like this:

>{field: "test"}

but this code:

var obj = {}
console.log(obj);
obj['field'] = 'test';

results in this console output:

> {}
  field: "test"

slightly different appearance, but same data. It's a result of the object being mutated after the console log statement. Not exactly sure why, but that is how chrome handles it.

It's clear that the console is providing a pointer to the object's location in memory, and not a copy of the data at the time of the console.log statement. hope that helps.

Related