I have a constructor for a model (similar to Backbone model) which uses an instance of a store (e.g. MongoDB / Redis) which is passed to the model factory. Now inside the constructor for the model, I do
this.store = options.store;
Store is now available as this.store once I construct an instance with var model = new Model().
Then I faced a situation when I my Model has "public" methods, e.g. Model.find() which will work without instantiating the model. But now because it's not been instantiated, functions inside Model can not access store by this.store.
What I did, is I started also adding store to the constructor itself Model.store = options.store which fixes the problem. But now store is exposed to anything that uses Model constructor and this is not desirable.
I am guessing I am doing something wrong. So I would appreciate some help.
If I get what you're saying correctly, then I think what you want is to allow for a "static" find() method on Model without exposing the store variable. Javascript doesn't really have a formal private scope for classes, but you can get what you want using closures. Here's a fiddle:
http://jsfiddle.net/52FPy/
EDIT:
An updated fiddle to demonstrate various ways to expose/hide info using closures:
http://jsfiddle.net/52FPy/2/
Briefly:
var Model = function(){
var store = 'this is a store';
var Model = function(){
}
Model.find = function(){
return store;
}
return Model;
}()
This will "hide" the store variable in the way you want.
Related
I followed a AngularJS tutorial on http://www.tutorialspoint.com/angularjs/angularjs_services.htm
The method passed to CalcService service got me confused. Is Angular using revealing prototype or a different one. I was confused because that inner function declared in this.square should be private and not visible outside the context of the object. How Angular is able to access square.
mainApp.service('CalcService', function(MathService){
this.square = function(a) {
return MathService.multiply(a,a);
}
});
An AngularJS service is a very distinct thing.
When it's initialized, it gets newed. Take this as an example:
function CalcService() {
this.square = function() {
// square some stuff
};
}
// then in the controller, directive, or wherever,
// it gets initialized behind the scenes like this
new CalcService();
However, it gets initialized as singleton, meaning that there's only ever one reference to the object, even if the component where you register it attempts to re-initialize it (see my recent answer on singletons in AngularJS).
Not sure what you mean when you mention a "revealing prototype pattern", but the this , in the case of an AngularJS service, is simply implementing a non-prototypal method on a new, regular JavaScript object.
Keeping with the same example above, in "normal" JavaScript, you could call new CalcService().square(). JavaScript doesn't have any native notion of private methods (though there are ways of implementing "class" methods that appear to be private.)
var service = new CalcService();
service.square();
There's nothing "private" about that method, just like there's nothing "private" about methods that are attached to AngularJS service objects... The only thing remotely "private" about it is that it happens to belong only to that specific object by virtue of the this keyword.
In your example, you are passing a constructor function into the angular service DI method.
In the constructor function you assign a method to this.square .
Just try this without angular and you will see you it behaves thr same.
function Calc() {
this.square = function() {
console.log('we get here');
}
}
var calc = new Calc();
calc.square();
This is the main feature of Javascript's prototype object oriented model. This is plain old OO javascript.
Above answers does good explanation how service work but they don't explained how this which is newly created object is exposed.
Whenever you create a service angular create a new object of that function for you, and that's get return whenever its get inject in controller, directive, service, etc. Internally method uses prototype of function to create an this which is context of function. Lets look at below code how it work internally.
function CalcService(){
//The line below this creates an obj object.
//obj = Object.create(CalcService.prototype)
//this = obj;
//`this` is nothing but an instance of function/CalcService.prototype which is giving access to its property attached to this
var privateVariableExample = 'test'; //this is private variable of service.
this.square = function(a) {
//return multiplacation result from here
}
//return this;
}
var objectOfCalcService = new CalcService();
objectOfCalcService.square(1);
I am in doubt if the following design pattern would cause a memory leak.
I have been using it for some time with success, but I haven't seen this pattern used by others, so I'd like some confirmation if you see something wrong with it.
As from next month I have to start working on a large project, and I want to know for sure that I can use this without problems, or if I should use another strategy.
controller.js:
var Controller = function(options){
};
Controller.prototype.makeView = function(options){
options.controller = this;
options.otheroption = options.otheroption;
var view = new View(options);
};
Controller.prototype.getModel = function(options){
//--- Get model ---
var model = new Model();
var promise = model.fetch();
return promise;
});
view.js:
var View = Backbone.View.extend({
initialize: function(options){
this.controller = options.controller;
this.otheroption = options.otheroption;
},
getModel: function(){
var promise = this.controller.getModel();
promise.done(_.bind(function(model){
//Do something with the returned model instance
}, this));
};
});
Instantiate controller, eg. from the router, or another controller:
//--- Instantiate the controller and build the view ---//
var controller = new Controller();
controller.makeView(options)
To me, this doesn't look like a circular reference, because both the controller and view are declared as a local variable.
Yet the instantiated view can access the controller functions, which allows me to isolate the RESTful server interactions via models / collections that the view uses.
For me it would seem as if the only reference remaining would be the view that keeps a reference to the controller object.
What I do afterwards is clean up the view (I destroy the instance and its references when I don't need it anymore.
Your opinion on this pattern is highly appreciated.
My purpose is to isolate creation of views / server interactions in separate controller files: if you see holes in my method and have a better way of doing it, please share.
Thanks.
Short answer: There is no memory leak problem in the code you have posted. The view holds a reference to the controller, but not vice versa. So as long as the controller lives longer than the view, that reference does not keep your objects from being garbage-collected. I don't see a circular reference anywhere in your code.
Longer answer: The pitfalls would be in the code you haven't posted. In particular, any event handlers in your view must be cleaned up properly, otherwise your views never fade into oblivion. But you have said in your question that you clean up your view, so I guess you are aware of that sort of problem.
What controller doing is here looks like a utility to me. Could have been easily managed by a global level singleton. I see some issues in first glance.
Code repetition, assuming you would creating separate Controller for different types of Models and Views, makeView and getModel code needs to be repeated for each controller. If you extending from a BaseController, then you need to pass View and Model Class to getModel and makeView functions.
How do you handle a use-case where you have to use same model in different Views?
makeView and getModel is designed assuming for each makeView there would be a getModel call, in assumed order
I would rather write a utility function which can create and deploy views for me.
var deployView = function(view, config){
//do the view rendering
view.render();
view.$el.appendTo(config.el);
}
var createView = function(config) {
var view;
var viewType = 'model';
if (config.collection || config.Collection) {
viewType = 'collection';
}
if (viewType === 'model') {
if (config.Model) {
config.model = new config.Model(config.modelAttributes);
//fetch if needed
}
} else {
if (config.Collection) {
config.collection = new config.Collection(config.items);
//fetch if needed
}
}
var filteredConfig = _.omit(config, 'Collection', 'Model', 'View');
view = new config.View(filteredConfig);
deployView(view, filteredConfig)
}
JavaScript implementations haven't had a problem with circular references for a long time. (IE6 did have a memory leak from circular references if I recall correctly, which wasn't shared by any other major browser from that period.)
Modern JavaScript implementations perform garbage collection through a "mark and sweep" algorithm. First they scan through your web app's entire memory structure starting from the global object, and mark everything they find. Then they sweep through every object stored in memory and garbage collect anything that wasn't marked. As long as there isn't a reference to your object from the global object or any stored function, it can be garbage collected.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Mark-and-sweep_algorithm
You're probably thinking of a reference counting-based implementation, which does have issues with memory leaks from circular references. In that implementation as long as one object contained a reference to another, that second object can't be garbage collected. That method was once used in web browsers but not anymore.
Nowadays, most memory leaks are from globally-accessible objects you forget to clean up and accidentally retaining data in function closures (a function that creates another function and passes/saves it somewhere). Since the closure's local variables can be accessed by the function created inside of them, they have to be retained as long as that function exists.
So go ahead and add all the circular references you want. Unless you need to target IE6, your code's fine.
I am building an application using Durandal and I have the need to share some functionality across view models.
I have 5 screens to build and they are all virtually the same screen except that in the activate function they will call to a different api end points but otherwise the view and view models will be identical.
Is there a pattern that I should be following to structure this correctly to promote code reuse?
If the views and the view models are identical except for calling different api actions, what about just taking in a parameter as part of the route? Then in the activate function, you can switch on the parameter. The route values can be designated so that your url is relevant, like [http://site/page/subtype], where subtype is the parameter (instead of using numeric values)
Regarding inheritance, depending on the features you need, there's so many ways to do JavaScript inheritance it can be a little confusing. There are some full-featured inheritance models provided by libraries such as base2 and Prototype. John Resig also has an inheritance model that I've used successfully.
In general, I prefer to stick to simpler solutions when it comes to JS inheritance. If you need a pretty much the full set of inheritance features, those libraries are good to consider. If you only really care about accessing a set of properties and functions from a base class, you might be able to get by with just defining the view model as a function, and replacing the function's prototype with the desired base class. Refer to Mozilla's Developer Docs for good info on inheritance.
Here's a sample:
//viewModelBase
define(function (require) {
"use strict";
function _ctor() {
var baseProperty = "Hello from base";
function baseFunction() {
console.log("Hello from base function");
}
//exports
this.baseProperty = baseProperty;
this.baseFunction = baseFunction;
};
//return an instance of the view model (singleton)
return new _ctor();
});
//view model that inherits from viewModelBase
define(function (require) {
"use strict";
function _ctor() {
var property1 = "my property value";
function activate() {
//add start up logic here, and return true, false, or a promise()
return true;
}
//exports
this.activate = activate;
this.property1 = property1;
};
//set the "base"
var _base = require("viewModelBase");
_ctor.prototype = _base;
_ctor.prototype.constructor = _ctor;
//return an instance of the view model (singleton)
return new _ctor();
});
Keep in mind this example all results in what effectively is a singleton (i.e. you'll only get the same instance, no matter how many times you require() it)
If you want a transient (non-singleton) just return _ctor. Then you'll need to instantiate a new instance after you require() it.
One more note, in general, functions should be defined on the prototype, not within the constructor function itself. See this link for more information on why. Because this example results in only a single instance, it's a moot point, so the functions are inside the constructor for improved readability and also the ability to access the private vars and functions.
I am new to the world of Javascript frameworks and I really like the way Backbonejs works.
But I have one question regarding the constructors of Models and Views. I have developed for years using Java like languages, and I am used to define constructors like this:
public Car(Manufacturer manufacturer, String model, Color color) {
this.manufacturer = manufacturer;
this.model = model;
this.color = color;
}
But I see in the documentation and in other tutorials that people usually don't declare a specific constructor when defining a Model or View, and they just construct objects like this:
var car = new Car({manufacturer: ford, model: "Mustang", color: "red"});
Is it wrong or "ugly" to define a constructor like:
window.Car = Backbone.Model.extend({
initialize: function(manufacturer, model, color) {
this.manufacturer = manufacturer;
this.model = model;
this.color = color;
}
});
If so, can you explain why ?
I really hope this is not a stupid question, I have not found any related questions.
Your idea of passing in multiple arguments rather than an object is fine, however you would want the initialize function to look like this:
window.Car = Backbone.Model.extend({
initialize: function(manufacturer, model, color) {
this.set({
manufacturer: manufacturer,
model: model,
color: color
});
}
});
You need to use set to access the attributes object. By using this you are attaching the attributes directly to the model.
The reason that backbone uses the attributes object is so that it can automaticaally trigger events when you change attributes. It is also a way to encapsulate your fields in methods, in the same way you would create
private Manufacturer manufacturer;
and
public Manufacturer getManufacturer()
in java.
It's similar to passing a context object to a method in Java (which is done where you need to pass some state to a method in a stateless environment). It just happens that the method is a constructor. I don't think there is a specific official pattern for this. This is a common paradigm in javascript.
I am trying to do some javascript test driven development, and would like to replace a dao with a mock one.
Lets say I have an object myObject that has a private var dao that I would like to create a setter for:
var dao = new RealDao();
function funcUsesDao() {
dao.doStuff();
}
Then in another file I have a handle to an instance of this object and want to add a setter so I can do the following:
var mockDao = {function doStuff() { /*mock code */}};
myObject.setDao(mockDao);
myObject.funcUsesDao(); should use mock dao
Environment specifics are this is node.js and the object I have a handle to is obtained by doing var myObject = require('../myObject');
You would use a constructor for the class, setting the dao to RealDao and then in the setDao you would set that dao to the new dao. Alternately in the constructor you would put a reference to dao, and on null, assign it to a new RealDao(). (at least, that's been my understanding of how people generally assign new interfaces for testing .. via the constructor)
//something like this
function Dao(interface){
this.dao = interface || new RealDao();
}
Otherwise, what you listed above is accurate. you just have to provide the setDao method as you indicated in your code.