Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right way of referencing Javascript Objects inside Objects

I'm a newbie to JavaScript, and I'm not very sure about the following legacy knockout and JS code which is being used in my app:

file1.js:

var FbPicturesObj = {
    fbPicturesVM: new FbPicturesVM(),
    initialize: function () {
        ko.applyBindings(FbPicturesObj.fbPicturesVM, $("#fb-albums")[0]);
        ko.applyBindings(FbPicturesObj.fbPicturesVM, $("#fb-album-photos")[0]);
    },
    Reset: function Reset() {
        FbPicturesObj.fbPicturesVM.albums([]);
        FbPicturesObj.fbPicturesVM.photos([]);
    }
}

file2.js:

function FbPicturesVM() { 

...... some code ....
 }

My question are:

  1. Does each call to FbPicturesObj.fbPicturesVM will create a new instance of fbPicturesVM in memory?
  2. Are the ko.applyBindings calls are written correctly? (in terms of code optimization)

Thanks a lot.

like image 940
badigard Avatar asked Oct 18 '22 20:10

badigard


1 Answers

File1.js contains a definition of a JavaScript object, more exactly a "literal object creation".

Inside it, each propertyName: value pair declares an initializes a new property, so that code is run only once, when creating the object. For example fbPicturesVM: new FbPicturesVM()

Properties of JavaScript objects can be functions, like this: initialize: function () {...},. In this case, whenever you run FbPicturesObj .initialize this function will be run.

The calls to ko.applyBindings are correct. This method expects the viewmodel object and an optional DOM element as the second parameter. A jQuery expression is (not exactly) an array of selected DOM elements, so this $("#fb-album-photos")[0] extracts the first DOM element of the jQuery expression, as needed by ko.applyBindings.

NOTE: as you suspect, the way of defining the model is not the best possible, to say the least. You can use the Revealing Module Pattern, which makes things much easier.

Revealing Module Pattern

In few words:

var vm = (function() { // declare a function
   // create variables and functions
   var name = ko.observable();
   var age = ko.observable();
   var _privateVar = 'Yuhu'; // won't be revealed
   var incAge = function() {
      age = age + 1;
   };
   // reveal only what you want, by returning it in an object
   return {
     name: name,
     age: age,
     incAge: incAge
     // note that _privateVar is not exposed, but could be
   }
})(); // This invokes the function, so that it return the model

NOTE the pattern Immediately-Invoked Function Expression (IIFE).

var value = (function() {/*return something*/})(); 

This pattern defines an anonymous function, that returns something. The () at the end runs it, so that the value is returned, and stored in value;

I recommend this patter because it's extremely easy to use and little error prone. Classical prototypal inheritance, constructor, and things like that are much harder to work with.

You can easyly convert this in a view model factory (something similar to a constructor, but not eactly a js constructor) by removing the invocation - () at the end - and storing the funcion definition, so that you can call it repeatedly.

var factory = function() {/*return something*/}; 

var vm1 = factory();
var vm2 = factory();
like image 65
JotaBe Avatar answered Nov 15 '22 03:11

JotaBe