Reputation: 850
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:
FbPicturesObj.fbPicturesVM
will create a new instance of fbPicturesVM in memory?ko.applyBindings
calls are written correctly? (in terms of code optimization)Thanks a lot.
Upvotes: 5
Views: 202
Reputation: 39065
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.
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();
Upvotes: 3
Reputation: 850
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.
Upvotes: 0
Reputation: 2452
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.
Upvotes: 0