4

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>
VanAlbert
  • 2,299
  • 1
  • 21
  • 17
  • 1
    Does running this in the chrome console give you the little 'i' that says :evaluated just now'? – Seth Lutske Jun 25 '20 at 22:40
  • @Seth Lutske - yes, it does. – VanAlbert Jun 25 '20 at 22:44
  • 1
    You're calling `appController.getAppobj();` (which contains the log statement) *before* you call `appController.initmyAppControllerFunction();` which creates the properties – Bergi Jun 27 '20 at 15:20
  • @Bergi, I know the log statement comes before the properties are created. I guess my question is why the log statement produces a list of properties anyway when I'd actually expect an empty object, like the SO console outputs. But I guess that's just the way FF and Chrome do things wrt sync vs async. I can live with that -- Thanks! – VanAlbert Jun 27 '20 at 15:34

1 Answers1

3

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.

Rick
  • 1,710
  • 8
  • 17
  • Thanks - I will look into this tomorrow, that seems like a plausible explanation. – VanAlbert Jun 26 '20 at 01:52
  • I edited the question to include the code. Your answer makes sense but with all respect it doesn't explain why different consoles handle this case so differently. The SO code snippet console shows the object as empty, FF shows it the properties but no ellipses, Chrome shows nothing to distinguish it from a non-empty object. I'll gladly accept your answer as correct but I'd like to see if anyone can provide a more complete answer first. – VanAlbert Jun 27 '20 at 12:53
  • added some details to my post. – Rick Jun 27 '20 at 15:09
  • I went ahead an accepted your answer. @Bergi has deemed this to be a dupe of a wider topic and closed the question, so that's that. – VanAlbert Jun 27 '20 at 15:31