I'm working on a proprietary site, and I'm having some issues. I'm using jQuery along with prototype, and I've got it namespaced properly, so in this question assume you can use $ or jQ as a namespaced reference to jQuery.
So I've got a bunch of functions, some mix jQuery and javascript, some plain javascript, some jQuery only. Now, currently some functions are defined within the document.ready jQuery function, and some are defined outside of it, kind of like this:
jQ(document.ready(function($) {
if ( ifConfig ) {
//page check, function calls here
fnc1();
fnc2();
fnc3();
fnc4();
}
function fnc1() {
//fnc code in here
}
function fnc2() {
//fnc code in here
}
}); //end document.ready
function fnc3() {
}
function fnc4() {
}
Now this is all pseudo code, you can assume the functions are valid and have valid code in them. Recently I was doing some debugging, and one of my functions that was declared and called inside the document.ready said it was undefined. I moved it outside of the document.ready, and everything worked again.
I'm basically trying to understand the order of how functions are initiated/called better, so my question is when do you declare functions inside the document.ready and when do you declare them outside? Do you only declare inside when they're called within that document.ready only? Or should I always just declare them outside of that document.ready?
Thanks.
Generally, you should declare & define your own namespace, where all of your application logic (including functions/methods) is located. That way you avoid collision with other scripts on your site + that way your code is much cleaner and easier to maintenaine.
var myapp = function(){
var foobar1 = null,
foobar2 = null,
foobar3 = null;
return {
getFoobar1: function(){
return foobar1;
},
getFoobar2: function(){
return foobar2;
},
setFoobar1: function(foo){
foobar1 = foo;
},
clickhandler: function(e){
alert('I am an event handler, and I am not anonymous');
}
// etc.
};
};
$(document).ready(function(){
var Application = myapp();
Application.getFoobar2();
$(document).bind('click', Application.clickhandler);
});
That pattern (some call it the "method pattern") creates a closured function/object which also guarantees private member variables within your namespace, only accessible through the getter functions from the outside.
This is really only a pretty basic example, you can push this idea & pattern to an extend, which is very nice & a good thing (IMO).
A great book about this stuff which was named and recommended pretty often is "Javascript: The Good Parts" by Douglas Crockford.
If a function is only used inside the document ready function, then declare it inside so you don't pollute the global scope. Otherwise, declare it outside so it the rest of your script has access to those functions.
(document).ready is more used for things that need to be executed at page load, and not function declarations. If you declare them inside of (document).ready, their scope will be local to that block - if they're only used locally, that's fine and they should be declared there. Otherwise, declare them outside.
So in your example, if the functions are only used in that block, they should be declared in there. If they're used other places additionally, they should be declared outside.
Related
I've been seeing a number of people wrapping their controllers with:
function(){
//CODE
}();
What's the benefit / goal there?
That isn't really anything related directly to Angular, it is a JS pattern know as an Immediately Invoked Function Expression.
It is one of the most useful patterns in JavaScript, primarily because of:
Code Encapsulation
Since functions have closures in JS, we can use this pattern to create private data very easily:
var index = (function iife() {
var counter = 0; // <-- this is private, only available inside the closure of inner()
return function inner() {
return counter++;
};
})();
console.log(index()); // 0
console.log(index()); // 1
console.log(index()); // 2
console.log(index.counter) // undefined
We can also pass arguments into an IIFE, which allows us to control how we access the outside context of our IIFE. For example, to make sure $ is actually the jQuery object within your code:
(function ($) {
// here have access to the global jQuery as $ regardless of what window.$ is and
// how many libraries are trying to use $
})(jQuery);
By combining the two ideas above, IIFEs can also be used to implement the module pattern, which is the basis for how RequireJS and NodeJS separate code:
var myModule = (function iife(initData) {
// we can use initData here to initialize our module if necessary
var module = {};
// private vars ...
var privateVar1, privateVar2;
// private methods ...
function privateMethod() {
console.log('yeeey');
}
module.somePublicProperty = 1;
module.somePublicMethod = function() {
privateMethod();
};
return module;
})(/* pass initialization data */);
myModule.somePublicMethod(); // 'yeeey'
The reason you'll find a lot of JavaScript code wrapped in an anonymous function is to isolate it from other code on the page.
The following code will declare a variable called name on a global scope:
var name = "Hello World";
By using that code, any other script on the page attempting to use a variable called name could potentially get an unexpected value of "Hello World" because your script declared it as "Hello World".
By wrapping that code in an anonymous function, you keep the code from conflicting with other variables called name:
(function() {
var name = "Hello World";
})();
In the example above, name is now only available inside of the scope of the anonymous function. It is not global, and therefore cannot conflict with other code on the page.
By wrapping your Angular module in an anonymous function, you prevent your code from conflicting with other code.
Additionally, other people who may use your code won't have to worry about it changing their global scope.
IMHO it's not necessary, even superfluous, as most controllers are already functions:
'use strict';
angular.module('MyApp').controller('AboutController', ['$scope'
function ($scope) {
$scope.title = 'About Us';
}
]);
Everything #nem035 and #tcasey said is correct but it also have another side effect.
If you use tools like Grunt or Gulp it also allow you to have working dists to put in production.
If you do not use Immediate Invoke Pattern you'll most likely have minification problems like:
State X is already defined!
Unknown provider
. . .
I suggest you to wrap all your js modules with this pattern.
I hope I've been helpful.
There are many benefits of you immediately-invoked-function-expression short IIFE and it's best practice to use it. This way each of angular service or controller become isolate and you don't run into global variables as it can happened if you don't use IIFE.
read more about it
Should I use addEventListener in these type cases?
<input id="input" type="file" onchange="fun()>
or
document.getElementById("input").addEventListener("change", function() {
fun();
});
and why?
The onchange attribute requires the fun function to be in global scope. In a larger application you want to avoid this, as there might be other functions with the same name from your application or from external libraries. Or imagine building a component that is used several times on the page.
addEventListener can be wrapped in a closure like this and be used inside an isolated component:
(function(){})(
function fun(){
// Now other components can also have a `fun` function, without causing confusion.
// `fun` is only defined inside the IIFE (the (function(){})() wrapper around the module).
}
document.getElementById("input").addEventListener("change", function() {
fun();
});
);
I have a jquery function like this:
(function($){
$.fn.myjqfunction = function(cfg){
var foo1, foo2;
return this.each...
};
})(jQuery);
How can I make foo1 and foo2 to be accessible from outside (from another function like this)?
These variables will store the state of some things that affect the entire document, and I want the other function to be aware of that...
Declare them outside the function, i.e., global.
You may want to put them in a namespace/object/module to be on the safe side. Which method is best depends on what you're actually doing with them.
For example, if they're related to specific selectors, it might be "best" to attach them directly to the DOM elements using .data, or keep them inside another jQuery function, etc.
Set up your function like this:
(function($){
function myjqfunction( cfg ) {
return this.each( ... );
}
$.myjqfunction = {
foo1: ... ,
foo2: ...
};
$.fn.myjqfunction = myjqfunction;
})(jQuery);
Then from outside your plugin, code can refer to $.myjqfunction.foo1 to get at those variables, and you'd refer to them the same way from inside your plugin code.
There are of course other similar ways to set that up.
I'm currently diving into Spine and I'm currently asking myself what would be the most elegant way to define a private function, using Spine's class creation method.
var PrinterManager = Spine.Class.create({
init: function () {
},
getAllAvailablePrinters: function () {
},
printDocument: function () {
}
});
(function () {
var instantiateActiveX = function(){
console.log("...");
}
PrinterManager.include({
pubInitActiveXPrinter: function(){
instantiateActiveX();
}
});
})();
As you can see I want instantiateActiveX to be private and not visible to the outside. Using the JavaScript closure function trick, I can make it private without any problems, but this solution doesn't seem too elegant to me in the contest of creating classes like Spine does.
The code works, i.e. I can call PrinterManager.init().pubInitActiveXPrinter() which will then internally call the private function and - correctly - I cannot call PrinterManager.init().instantiateActiveX().
My Question - Is there a more elegant way to do it with Spine that I didn't yet discover??
Well to put it simple, there's no way other than closures to make some function/variable invisible/private from the global scope.
No.
"private" functions don't exist. You only have local functions and closure state. And using local functions/variables and closures for state does not mix well with using prototypical inheritance.
The real question you should be asking is "why do you need private functions" because you don't.
If a function is unstable and shouldn't be used because the API might change just prepend it with _
var PrinterManager = {
...
_instantiateActiveX: function() {
...
}
}
If anyone uses these internal functions or variables then they have no right to complain when their code breaks if you change it.
I want to be able to test some inner functions that I have without putting the Javascript test code in the same file. I've been trying to inherit the class that has the inner functions, and then adding wrapper functions to make them public, like this:
copyPrototype(TrafficChartCanvas_test, TrafficChartCanvas);
function TrafficChartCanvas_test() {
TrafficChartCanvas_test.prototype.test_getYScale = function(reach) {
return getYScale(reach);
}
}
Assume copyPrototype successfully assigns the prototype of TrafficChartCanvas to that of TrafficChartCanvas_test. Here's part of the file I'm attempting to test:
function TrafficChartCanvas(...) {
// some other stuff here... public functions, etc.
function getYScale(reach) {
...
}
}
However, this doesn't work for me. Is there any other way I can do this?
getYScale isn't part of TrafficChartCanvas's prototype, it's within its closure. They're two very different things.
You could change the way you create TrafficChartCanvas and restructure your code something like:
TrafficChartCanvas.prototype = {
// (... Other functions ...)
getYScale: function() {
...
}
}
This puts the function in the prototype and allows it to be tested using tests written and included in another file. You can't keep functions private within a closure and make the accesible for external testing; you'll have to go the prototype route.
The "TrafficChartCanvas" function can arrange for a way to explicitly export the function, but short of that, no there's no way to do it.