5

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.

1
  • The only bad thing I see here is the array access being unchecked. If there's no #fb-albums or #fb-album-photos on page there's gonna be an error Commented Dec 16, 2015 at 11:35

3 Answers 3

3

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();
Sign up to request clarification or add additional context in comments.

4 Comments

@Liam Thanks for your comment, but I'm intentionally using value to explain that IIFE is an usual JS pattern that can be used for lots of different things, not only for creating view models... or am I missing some mistake in my explanation?
ah, sorry, I see what your saying now
Putting the function-invocation parentheses outside the parentheses enclosing the function definition is the "dog balls" pattern. :) youtube.com/watch?v=eGArABpLy0k
Thanks a lot for the detailed explanation
0

The constructor for FbPicturesVM only invokes when the FbPicturesObj object is instantiated (in your example, this will just be when the script is included in the page). So, in terms of memory, you have just the one instance and you're then passing references to it (JS passes objects by reference mostly).

I dont know knockout very well but theres nothing syntactically wrong and passing an object and an element sounds about right for binding code.

Comments

0

This question should be split up, because the first question is unrelated to Knockout, and more to do with how object literals are associated with instantiated objects.

So for question 1, the answer is "no" because FbPicturesObj saves the instantiated property, FbPicturesObj.fbPicturesVM

Consider the following:

var Person = function(name) {
	this.name = name
}

Person.prototype.sayName = function() {
	return this.name
}

var people = {
	fred : new Person('fred')
}

console.log(people.fred.sayName()); // returns 'Fred'

var people = {
	fred : new Person('jane')
}

console.log(people.fred.sayName()) // returns 'jane' and not 'fred'

var people = {
	fred : new Person('fred'),
  jane : new Person('jane')
}

console.log(people.fred.sayName()) // returns 'fred'
console.log(people.jane.sayName()) // returns 'jane'

In this case each call to 'person.fred' will refer to the same instance always, because its saved to the people object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.