This may have already been asked lots of times, and I've searched around SO but so far all the answers I read aren't exactly what I'm looking for.
I'm working on a website with moderate DOM elements showing/hiding, some AJAX calls, and probably something else. So I'll be having two main script files (HTML5 Boilerplate standard)
plugins.js // third party plugins here
site.js // all my site specific code here
Previously I'm using object literal design pattern, so my site.js is something like this:
var site = {
version: '0.1',
init: function() {
site.registerEvents();
},
registerEvents: function() {
$('.back-to-top').on('click', site.scrollToTop);
},
scrollToTop: function() {
$('body').animate({scrollTop: 0}, 400);
}
};
$(function() {
site.init();
});
So far so good, it's nicely readable, all methods are public (I kinda like this, as I can test them via Chrome Dev Tools directly if necessary). However, I intend to decouple some of the site's functionality into more modular style, so I want to have something like this below the code above (or in separate files):
site.auth = {
init: function() {
site.auth.doms.loginButton.on('click', site.auth.events.onLoginButtonClicked);
},
doms: {
loginButton: $('.login'),
registerButton: $('.register')
},
events: {
onLoginButtonClicked: function() {
}
},
fbLogin: function() {
}
};
site.dashboard = {
};
site.quiz = {
};
// more modules
As you can see, it is very readable. However there is one obvious downside, which is I have to write code like site.auth.doms.loginButton and site.auth.events.onLoginButtonClicked. Suddenly it becomes hard to read, and it will only grow longer the more complex the functionality gets. Then I tried the modular pattern:
var site = (function() {
function init() {
$('.back-to-top').on('click', scrollToTop);
site.auth.init();
}
function scrollToTop() {
$('body').animate({scrollTop: 0}, 400);
}
return {
init: init
}
})();
site.auth = (function() {
var doms = {
loginButton: $('.login'),
registerButton: $('.register')
};
function init() {
doms.loginButton.on('click', onLoginButtonClicked);
}
function onLoginButtonClicked() {
}
return {
init: init
}
})();
// more modules
As you can see, those long names are gone, but then I guess I have to init all other modules in the site.init() function to construct them all? Then I have to remember to return the functions that need to be accessible by other modules. Both of them are okay I guess albeit a bit of a hassle, but overall, am I onto a better workflow working with modular pattern?
The correct answer, here, of course, is: "it depends".
If you're totally okay with all data and all methods, for every section of your site being 100% public, then just using a single literal (or multiple literals), with nested objects if desired, is totally fine, assuming that you can keep it from turning into one gigantic ball of code.
If you want any kind of private state, which has any kind of persistence (ie: doesn't reset every time you run a function), then the revealing-module is great.
That said:
It's not a requirement of the revealing-module for you to have an .init method, at all.
If your module can be self-contained, then just focus on exporting what you WOULD like to make public.
To this end, when I'm writing code which a team might look at, later, I'm finding myself creating a public_interface object and returning it (the named version of the anonymous object you return).
The benefit of this is minimal, except to add the understanding that anything which needs to be made public needs to be appended to the interface.
The way you're currently using it:
var module = (function () { /* ... */ return {}; }());
module.submodule = (function () { /*...*/ return {}; }());
Is no better or worse than literals, because you can just as easily do this:
var module = {
a : "",
method : function () {},
meta : { }
};
module.submodule = {
a : "",
method : function () {},
meta : { }
};
Until you hit something which doesn't work for you, work with what fills your needs.
Personally, I'll typically build any data-only objects as literals: config-objects, objects which come in from other connections, etc...
Any dirt-simple object which requires maybe one or two methods, and can be built by nesting only one or two levels deep, I might build literally, as well (as long as it doesn't require initialization).
// ex:
var rectangle = {
width : 12,
height : 24,
area : 0,
perimeter : 0,
init_area : function () { this.area = this.width * this.height; return this; }, // buh...
init_perimeter : function () { this.perimeter = (this.width * 2) + (this.height * 2); return this; } // double-buh...
}.init_area().init_perimeter();
If I needed several of these, perhaps I'd make a constructor.
But if I only ever needed one of something unique like this, wouldn't it save me some headaches to just do something like this:
var rectangle = (function (width, height) {
var public_interface = {
width : width,
height : height,
area : width * height,
perimeter : (2 * width) + (2 * height)
};
return public_interface;
}(12, 24));
If there were more-advanced calculations required, I could keep any extra vars private, and work on them from the inside.
If I needed to have sensitive data inside of an object, and functions to work on that data, then I could have public-functions which call those private functions, and return results, rather than providing access.
Also, if I refactor my code, and decide to rename rectangle at some point, then any functions nested 3 or more deep, which are referring to rectangle will have to be modified, as well.
Again, if you're structuring your methods so that they don't need to directly ask for any object which is further up than this, then you won't have this problem...
...but if you have an interface that looks like:
MyApp.myServices.webService.send();
and it's expecting to find:
MyApp.appData.user.tokens.latest; // where personally, I might leave tokens in a closure
If you change the structure of your appData module, you're going to have all kinds of errors in your webService module, until you find every reference to the old format, and rename them all.
Related
I am sure this has been asked before, but not able to find it ... so I'll give it a try.
Wen coding projects that consist of multiple domains I usually divide them into two groups.
If it should be only one instance – ever – I use static objects. Utilities also quickly land here.
Else use prototype.
As an example I have a project where there a cache is maintained. As there should only be one cache it is typically written as:
var cache = {
head : null,
tail : null,
clear : function () {
cache.head = null;
cache.tail = null;
...
},
add : function () { ... },
remove : function () { ... },
...
};
Or something like:
var cache = {};
cache.push = function (d) {
...
};
cache.flush = function (d) {
...
};
Other objects are meant to be duplicated, or might one day be, and are coded as:
function Foo() {
...
}
Foo.prototype.bar = function () {
...
};
Now; my question is if there are any particular disadvantages with this practice. In particular the way of producing static objects. Or, put the other way around; any particular advantages. Most things I find discuss the advantages of prototype when duplicating objects. Use of prototype instead of thisin constructor etc. Few address the particulars of static objects. Perhaps because it is straight forward?
Another example of static practice is e.g. glMatrix, for example with vec2.
I have tried searching through a lot of S.O. pages but nothing has touched EXACTLY on this top while also NOT USING JQUERY.... I am trying to stick to pure JavaScript as I want to learn it 115% before advancing my current knowledge of JQuery.
I have an object called ScreenResizeTool like this...
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg);
}, true);
}
and a method like this...
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
My trouble is probably obvious to an experienced JavaScript user but I am having trouble not making this into a messy dirty awful OOP set. I have done various tests to show and prove to myself that the this inside the addEventHandler changes when it becomes bound to the window. This much I assumed before testing but I was able to see that once window.resize event happens the listen method is gone and not a part of the global window variable....
I have also tried adding a this capture such as this.me = this inside the object constructor however it also couldn't see the me variable once it ran. Once the window took the function over it no longer knew anything about the me variable or any reference to my class methods....
I am aware that I could separate this differently but my goal here is to learn how to fully encapsulate and use as many clean OOP structures as possible as I just came from the .NET world and I need it in my life.
I am also aware that I could make messy calls and or store this object or access to the methods inside the window variable but that seems outright wrong to me. I should be able to fully encapsulate this object and have its events and methods all implemented in this class structure.
I also know that the currImg variable is not going to be seen either but lets start small here. I assume once I figure out my incorrect train of thought on scope for JavaScript I should be fine to figure out the currImg problem.
I know there's 1000 JavaScript programmers out there waiting to rip me a new one over asking this simple question but I gotta know...
Thoughts anyone?
this inside a function bound to a DOM Object (like window) will always refer to that object.
this inside a constructor function will always refer to the prototype.
A common practice to circumvent the this issue, as you mentioned, is to cache it in a variable, often called self. Now you want the variables and properties of your object available after instantiation, so what you need is the return keyword, more specifically to return the parent object itself. Let's put that together:
function ScreenResizeTool() {
var self = this;
// method to instantiate the code is often stored in init property
this.init = function() {
window.addEventListener('resize', function() {
self.listen(); // self will refer to the prototype, not the window!
}, true);
};
return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
var h = window.innerHeight, w = window.innerWidth;
console.log('Resized to ' + w + ' x ' + h + '!');
};
Pretty easy huh? So we have our prototype now, but prototypes can't do anything if there's not an instance. So we create an instance of ScreenResizeTool and instantiate it with its init method:
var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!
You could also simply store the listen & init methods as private functions inside your constructor, and return them in an anonymous object:
function ScreenResizeTool() {
var listen = function() { ... };
var init = function() { ... };
// in this.init you can now simply call listen() instead of this.listen()
return {
listen: listen,
init: init
}
}
Check out the fiddle and make sure to open your console. Note that in this case I'd rather use the first function than the second (it does exactly the same) because prototypes are only useful if you have multiple instances or subclasses
The whole concept of this in JavaScript is a nightmare for beginners and in my code I usually try to avoid it as it gets confusing fast and makes code unreadable (IMHO). Also, many people new to JavaScript but experienced in object-oriented programming languages try to get into the whole this and prototype stuff directly though the don't actually need to (google JS patterns like IIFE for example as alternatives).
So looking at your original code:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg); // global function listen?
}, true);
}
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
First off, you probably mean addEventListener instead. In its callback you refer to listen but as a global variable which would look for it as window.listen - which doesn't exit. So you could think to do this:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
this.listen(currImg); // what's this?
}, true);
}
As you want to use the prototype.listen function of ScreenResizeTool. But this won't work either as the event listener's callback function is called with a different this and not the this that is your function scope.
This is where something comes in which makes most programmers cringe, you have to cache this, examples from code I've seen:
var _this = this;
var that = this;
var _self = this;
Let's just use the latter to be able to refer to the function within the event callback:
function ScreenResizeTool(currImg) {
var _self = this;
window.addEventListener('resize', function() {
_self.listen();
}, true);
}
Now this will actually work and do what you want to achieve: invoke the prototype.listen function of ScreenResizeTool.
See this JSFiddle for a working example: http://jsfiddle.net/KNw6R/ (check the console for output)
As a last word, this problem did not have anything to do with using jQuery or not. It's a general problem of JS. And especially when having to deal with different browser implementations you should be using jQuery (or another such library) to make your own code clean and neat and not fiddle around with multiple if statements to find out what feature is supported in what way.
I'm very inexperienced with javascript so forgive me if this is really obvious...
I'm using the TodoMVC example found here (http://todomvc.com/architecture-examples/backbone/) as a foundation for a Cordova project. The trouble that I'm having is combining this with the Camera and Geolocation plugins, I get errors calling any functions in js/views/app-view.js from within the Camera/Geolocation callback functions. I'm assuming it's a problem of context but I don't know enough about javascript to fix it.
For example, the TodoMVC project adds new items using this line of code, in js\views\app-view.js:
app.todos.create(this.newAttributes());
I'm trying to combine this with the camera function to take a picture with a phone's camera, then add a new todo item with the picture stored in it. Everything works fine except when I try to have that above line of code in the camera callback function, at the bottom like this:
onCameraSuccess: function(imageData) {
// Stores image data in a hidden field to be used later. Not best method but it works
document.getElementById('imageData').value = "data:image/jpeg;base64," + imageData;
// This line should create a new item
app.todos.create(this.newAttributes());
},
It gives the error "Undefined is not a function", seemingly referring to "this.newAttributes()". Again it seems like this is a matter of context, because that very same line works almost anywhere else in the same script.
OnCameraSuccess is a callback function from the Camera's getPicture function:
Camera: function() {
navigator.camera.getPicture(this.onCameraSuccess, this.onCameraFail, { quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
targetWidth: 250,
targetHeight: 250,
correctOrientation: true
});
},
Likewise, a function for Geolocation requires two callback functions, for success and errors, but I can't find an acceptable way to refer to the other functions that doesn't give a TYPE_MISMATCH_ERR that says those aren't functions.
onDeviceReady: function() {
//This line calls the geolocation function and specifies the two callback functions, but it thinks they don't exist
navigator.geolocation.watchPosition(this.onLocationSuccess, this.onLocationError, {enableHighAccuracy : true});
},
onLocationSuccess: function(position) {
// map logic
},
onLocationError: function(error) {
alert('code: ' +error.code+ '\n' + 'message: ' +error.message + '\n');
},
They're right below the onDeviceReady function, but for some reason it can't find them. this.onLocationSuccess doesn't work (even though that's how it refers to all of its other functions), self.onLocationSuccess doesn't work... Again, it seems like a matter of context, but I can't figure it out.
Any ideas? I don't even know enough about javascript to know if I'm explaining this adequately, so feel free to yell at me about that too.
The value of this in JavaScript depends on how a function is called. For example, this:
var obj = {
f: function() { console.log(this) }
};
obj.f();
will put obj in the console but this:
var obj = {
f: function() { console.log(this) }
};
var f = obj.f;
f();
will (usually) dump window into the console even though the same function is being called. This this behavior confuses almost everyone when they start using JavaScript. In your case, the documentation doesn't say anything about what this will be in the getPicture callbacks so this is probably going to be window instead of your object.
If you need a particular this with a callback function in JavaScript, you usually have to arrange it yourself. One way to do that is to stash the desired this in a variable and use an anonymous function:
var _this = this;
navigator.camera.getPicture(
function(imageData) { _this.onCameraSuccess(imageData) },
...
);
A cleaner way (especially when there are arguments to your functions) is to bind the function to the desired this using $.proxy, _.bind, Function.prototype.bind, or similar utilities that come with pretty much every JavaScript toolkit. For example, given this:
var obj = {
f: function() { console.log(this) }
};
var f1 = $.proxy(obj.f, obj);
var f2 = _(obj.f).bind(obj);
var f3 = obj.f.bind(obj);
Calling f1(), f2(), or f3() will all dump obj into the console. Underscore is the typical toolkit with Backbone so this would be common:
navigator.camera.getPicture(
_(this.onCameraSuccess).bind(this),
_(this.onCameraFail).bind(this),
{ ... }
);
Underscore also provides _.bindAll, this is commonly used within initialize to bind several functions in-place:
initialize: function() {
_.bindAll(this, 'onCameraSuccess', 'onCameraFail');
//...
}
and then you can use this.onCameraSuccess without worry about the binding:
navigator.camera.getPicture(
this.onCameraSuccess,
this.onCameraFail,
{ ... }
);
Using _.bindAll in initialize would probably be the most common approach in Backbone.
Since you are passing this as a reference to the camera function it is being overridden by camera's context with the current context of the application.
Make a clone of the current context like
var currentContext = this;
currentContext.onCameraSuccess,
currentContext.onCameraFail
This is applicable where ever the application control is moving from one context to other eg:backbone view to underscore functions and moving back to callback function etc.
I'm trying to find a simple way to refer to the current instance of an object from the object methods itself (similar to this keyword in any decent language).
I've tried many variations of "storing a pointer for itself" (like window.window.window do), but always something go wrong. For example:
function ClassA() {
var mySelf = this;
this.myMethod = function() {
console.log(mySelf); //Once you extend this class, mySelf will not be available
}
}
function ClassB() {
this.mySelf = this; //Ok, now you can extend this and mySelf will be there
this.myMethod = function() {
console.log(mySelf);//"mySelf is not defined" because it's a property now
console.log(this.mySelf);//Value of 'this' and 'self' will vary
console.log(RandomContainer.ClassBInstance.mySelf);//I can't use a defined path
}
}
Since everything about OOP in JavaScript is hackish, I have to ask...
Is there any magic to refer to the current object that a method is being called from?
EDIT
A lot of possible solutions in the comments, thanks guys!
But I still need to improve my question. So I'll add some piece of code with my failed attempts, and then try out the proposed solutions...
function BaseController()
{
var myPriv = 42;
return {
getAnswer: function() {
return myPriv;
}
};
}
function SomeController()
{
return {
showAnswer: function()
{
var answer;
answer = myPriv; //I need some way to access this
answer = getAnswer(); //Also a way to refer to my own methods
//(I don't even find a way to call 'showAnswer' from this context)
console.log('The answer is ' + answer);
}
};
}
//That's how I was extending my classes so far...
var someControllerInstance = jQuery.extend(
new BaseController(),
new SomeController()
);
someControllerInstance.getAnswer(); //Works!
someControllerInstance.showAnswer(); //Reference errors...
take time to learn the idiosyncrasies of js, be warned though, it's like marmite.
If you'll allow me to be blunt for a moment, you are approaching JavaScript with the wrong frame of mind. It is not designed for classical inheritance, nor for protected properties or methods, and there is no benefit in bending it that way. To be honest I find towering stacks of inheritance a pain to read and navigate, unless you have a singing-all-dancing IDE that may take a week to load. The closer to flat and open you can achieve — whilst still keeping things flexible — the better you are at coding, and the more other coders that may take over your work will thank you. (obviously that is opinion)
For more information on prototype inheritance read the following informative post:
http://davidwalsh.name/javascript-objects-deconstruction
Below is an example of prototype inheritance, it should be noted that Object.create and isPrototypeOf are relatively new and do not exist for older JavaScript interpreters. Approximate polyfills can be used in most cases however.
Put simply JavaScript becomes much more powerful when you think in terms of objects borrowing methods from wherever they may be found, and not instances rigidly inheriting from slightly less specific instances; or worse, constructors that keep rebuilding the same functions again and again.
The following is just an example, and across my 16 years of coding ECMAScript I have barely ever needed anything that approaches classical inheritance, nor have I needed objects that heavily inherit on the prototype chain either. More often than not my js is basically just a number of newly created objects, properly name-spaced, that borrow methods from fixed pools of functions; any type detections are duck-typed, and I'm careful to keep everything as local as possible.
Anyway, here's something I don't often use:
var Make = function(construct){
return Object.create(construct);
};
var Extend = function(proto, props){
var instance = Object.create(proto);
for ( var i in props ) { instance[i] = props[i]; }
instance.super = proto; // this should never be needed really
return instance;
};
var Animal = {
keepBreathing: function(){
console.log('animal', this);
}
};
var Monkey = Extend(Animal, {
climbTree: function(){
console.log('monkey', this);
console.log('monkey', this.super);
}
});
var KeyserSoze = Make(Monkey);
KeyserSoze.keepBreathing(); /// animal, instance of KeyserSoze
KeyserSoze.climbTree(); /// monkey, instance of KeyserSoze
console.log('an instance of monkey', KeyserSoze);
console.log('has animal as proto', Animal.isPrototypeOf(KeyserSoze)); // true
console.log('has monkey as proto', Monkey.isPrototypeOf(KeyserSoze)); // true
Whilst the above does follow a kind of classical layout i.e. Monkey inherits methods from Animal, you could approach things in a different way. The following is more open to dynamic changes, in the fact you could switch out the behaviours object for another interface entirely. Again, this is just an illustration that you don't have to construct things in a fixed way.
Something I'm more likely to use:
var AnimalBehaviours = {
keepBreathing: function(){
(this.breathCount === undefined) && (this.breathCount = 0);
this.breathCount++;
}
};
var ApeLikeDescendant = (function( behaviours ){
return {
create: function( config ){
return Object.create(this).prep(config);
},
prep: function( config ){
/// do your instance specific set up here
return this;
},
climbTree: function(){
console.log('ape-like', this);
},
keepBreathing: function(){
return behaviours.keepBreathing.apply(this, arguments);
},
switchBehaviours: function(newBehaviours){
behaviours = newBehaviours;
}
};
})(AnimalBehaviours);
var DouglasAdams = ApeLikeDescendant.create({});
You could adapt the above to behave more in a manner similar to mixins i.e. you'd take the behaviours, step through them and merge them to the ApeLike object... it's really quite open to whatever your goal is.
Something that I use regularly:
var ElementEdgeCases = {
makeWorkOnNetscape47: function(){
this.target; /// Intentionally left almost blank.
}
};
var ElementFinagler = (function(){
var finagle = {
target: null,
prep: function( element ){
this.target = element;
return this;
},
addClass: function(){
var c = this.target.getAttribute('className'); /// and so on ...
return this;
},
elaborate: function( mixin ){
for ( var i in mixin ) {
if ( mixin.hasOwnProperty(i) ) {
this[i] = mixin[i];
}
}
return this;
}
};
return function( element ){
return Object.create(finagle).prep(element);
};
})();
var elm = document.getElementsByTagName('body')[0];
ElementFinagler(elm)
.elaborate(ElementEdgeCases) // extend the object if we need
.addClass('hello world')
;
The main thing to keep in mind with JavaScript is that no function is owned by anything, not really. Every time you execute a function, the function's context is implied by the way you call that function — the context is computed at call time. This allows a great deal of flexibility, and whilst you mention that calling function.apply(context, args) or function.call(context, arg, arg, ...) every time is cumbersome; it is very easy to codify your own system for hiding that repetition away.
Oh, and before I forget, one other thing to take away from the code above is that there is no duplication of function creation. Every instance shares the same functions in memory. This is an important thing to bear in mind if you are planning to create large scale applications, as you can quickly eat up memory with multiple instances of functions.
So just to recap:
Forget inheritance, it's rarely required for many js projects.
Create flexible objects that can be extended when required.
Borrow methods when you need them from other objects, using apply or call to change context.
Keep your code open, there is no need for private; open is more extensible.
Private no, but having properties not enumerable is a different story, see defineProperty.
Make sure you do not duplicate functions — unless you have to — instead create them once and reference.
this referrers to the dom node that an event originated from, or the javascript object it is a child of. In that order.
this.parentNode referrers the dom node's parent (Not sure if it works in object context).
When I write javascript I'll usually try to leverage the html's dom itself, nesting things mindful of how the JS needs to reference them.
I'm looking to encapsulate my javascript inside a namespace like this:
MySpace = {
SomeGlobal : 1,
A: function () { ... },
B: function () { ....; MySpace.A(); .... },
C: function () { MySpace.SomeGlobal = 2;.... }
}
Now imagine that instead of a few lines of code, I have about 12K lines of javascript with hundreds of functions and about 60 globals. I already know how to convert my code into a namespace but I'm wondering if there's a quicker way of doing it than going down 12K lines of code and adding MySpace. all over the place.
Please let me know if there's a faster way of doing this.
Thanks for your suggestions.
I like to wrap up the namespace like so. The flexibility is huge, and we can even separate different modules of the MySpace namespace in separate wrappers if we wanted too. You will still have to add some sort of _self. reference infront of everything, but at least this way you can change the entire name of the namespace very quickly if need be.
You can see how with this method you can even call _self.anotherFunc() from the 1st module, and you'll get to the second one.
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.test = function () {
alert('we got here!');
_self.anotherFunc(); // testing to see if we can get the 2nd module
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
$(function () {
MySpace.test(); // call module 1
MySpace.callOtherModule(); // call module 2
});
// Here we will create a seperate Module to the MySpace namespace
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.callOtherModule = function () {
alert('we called the 2nd module!');
};
_self.anotherFunc = function () {
alert('We got to anotherFunc from the first module, even by using _self.anotherFunc()!');
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
jsFiddle DEMO
Wrap a function body around your existing code to use as scope, hiding everything from global - this will allow you to do internal calls without pasting Namespace. prefix everywhere, neatly hide things you don't want everyone else to see, and will require minimal changes as well.
After that, decide what functions you want to "export" for everyone and assign them to properties of object you want to use as "namespace".