I have defined the following piece of Coffeescript code below, which defines a function using RequireJS:
define 'PersonService', ['jquery'] ($) ->
getPerson = (id) ->
person = dataService.GetPerson id
{ getPerson: getPerson}
It produces the following:
(function() {
define('PersonService', ['jquery'](function($) {
var getPerson;
getPerson = function(id) {
var person;
return person = dataService.GetPerson(id);
};
return {
getPerson: getPerson
};
}));
}).call(this);
I guess the issue I have is with the self-executing function that is produced from the Coffeescript code. Will this cause issues that I am possibly not tracking? Or is this proper.
Thank you.
It's correct
The difference between not having a wrapped function and having one is to do with scope.
If you define var a = 10; in the global scope a becomes global with or without the var keyword.
When wrapped all variables are local to the wrapped function so do not end up global.
In you example everything is already wrapped in a function so yes you don't need the extra wrapping!
You can tell coffee-script not to add the wrapper function using
coffee -b, --bare compile without a top-level function wrapper
IMHO: It's better to always have the wrapper function so you don't need to think about it on a file to file basis.
Related
Can someone explain how to do this properly
foo(); //outputs 'foo'
function foo(){
console.log('foo');
}
but this gives 'function is undefined' error
MY_NAME_SPACE ={};
MY_NAME_SPACE.foo(); //undefined
MY_NAME_SPACE.foo = function(){
console.log('foo');
}
I can see that in the second example, the call was made before the function was added to the My_NAME_SPACE object, but if this is the case,how would one use this type of "name space" if the ordering is important?
Yes, if you are going to use this namespace pattern, you will need to create and populate the namespace before trying to invoke methods or access property values that have not yet been assigned to the namespace.
Instead of defining the namespace object and then defining each consecutive method in the namespace, eg:
var MY_NAME_SPACE = {};
MY_NAME_SPACE.foo = function() {
console.log('foo');
}
I prefer to use what is referred to as the module pattern, as the methods that I want contained in MY_NAME_SPACE are visually wrapped in the module:
var MY_NAME_SPACE = (function () {
var foo = function () {
console.log('foo');
};
return { foo: foo };
})();
MY_NAME_SPACE.foo()
Also, if the methods you wish to wrap in a namespace or module are independent and reusable, it would makes sense to create a separate file, maybe my_name_space.js, and include this file in projects that need access to the methods in MY_NAME_SPACE (the MY_NAME_SPACE API).
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
I'm just getting started with javascript modules and I want to make sure I'm doing it correctly.
Below is an example of the methodology I'm following, based on the "Loose Augmentation Pattern" that I read about here
//myApp.js
var myApp = {};
//someModule1.js
(function (ma) {
ma.someModule1.DoStuff = function () {
alert("hi");
};
return ma;
}(myApp || {}));
//someModule2.js
(function (ma) {
ma.someModule2.DoMoreStuff = function () {
alert("ho");
};
return ma;
}(myApp || {}));
//someModule3.js
myApp.someModule1.DoStuff();
myApp.someModule2.DoMoreStuff();
The myApp variable within myApp.js would be the only variable that's globally exposed, with all of the other modules and their functions only being accessible via this variable.
someModule3.js isn't necessarily a module, but any arbitrary javascript wanting to access the properties of the myApp object (After the appropriate modules have been defined).
The part in particular I'm not 100% clear on is this: (myApp || {}, jQuery)
What is that part called and what exactly is it doing (I know the whole thing is a closure, but I just don't understand exactly how the last part is working)?
It seems like "ma" is initially nothing, I add a function to it in the body of the closure, then return ma. At this point myApp only has the one function.
In the bit at the end (myApp || {}), is it actually saying "ma isn't nothing, it's actually called myApp and I'll append those functions to that object if it exists."
Is that right or am I way off?
I see four issues:
Your code won't run as is. You have to define .someModule1 before you can assign to it.
There's no reason to do return ma because you aren't using the return value.
There's no reason to pass myApp || {} because if myApp is not defined, then your code will do nothing because the object you created would not be capture in any variable and will just be immediately garbage collected and not be accessible.
As you've shown your code, the IIFE you've enclosed the code in is not accomplishing anything other than adding lines of code and complexity.
Here's more detail on each issue.
Your modules won't run as is. You need to define .someModule1 by changing this and there is no reason in your code to pass myApp || {}:
//someModule1.js
(function (ma) {
ma.someModule1.DoStuff = function () {
alert("hi");
};
return ma;
}(myApp || {}));
to this:
//someModule1.js
(function (ma) {
// you must define .someModule1 before you can assign properties to it
ma.someModule1 = {};
ma.someModule1.DoStuff = function () {
alert("hi");
};
return ma;
}(myApp));
There is also no reason to do return ma in your code since you are not using the return value.
The reason myApp || {} is of no value here is because if myApp is not defined, then none of the code in your module does anything useful because the underlying object you would be assigning things to is not captured in a variable anywhere. So, if myApp is not defined, then your code accomplishes nothing. So, somewhat by definitino, myApp has to already be defined for your code to be useful, therefore, you can just pass myApp into the IIFE.
As you've shown the code, there is no benefit or reason to putting the assignment of properties inside the IIFE. You don't have any closure variables or anything that is private inside the IIFE. So, you would achieve exactly the same result with this:
myApp.someModule1 = {};
myApp.someModule1.DoStuff = function () {
alert("hi");
};
There are some reasons for using an IIFE, but you don't show any in this code example. Personally I'm a fan of using the simplest code that achieves your objectives and not adding extra complexity just for sake of it. Other people like to put all their code inside these IIFE modules. I only put my code inside an IIFE when there is actually a reason to have your code in an IIFE.
Is it possible to do achieve this behavior using node modules?
module.js:
module.exports = function () {
var test.fn = function () {
console.log("$test.fn()");
}
var test.fn2 = function () {
console.log("$test.fn2()");
}
var variable = "test";
};
app.js:
require("./module.js")();
test.fn();
test.fn2();
otherFunction(variable);
I dont want to do anything like this $ = require("./module.js")(); $.test.fn();
I want to inject this variables into app.js scope without wrapper variable.
Edit:
I have ended up using this:
module.js:
module.exports = function () {
eval(String(inject));
var inject = (
this.$module1 = {},
this.$module1.fn = function () {
console.log("$module1.fn()");
}
);
};
app.js:
require("./module.js")();
$module1.fn();
The top level scope in a module is actually a function scope (the node.js loader wraps each module in a function that it then calls to execute the code in the module). Thus, there is no publicly available "root" object that we can programmatically assign properties to.
So, that means that it is not possible in a module to programmatically add new variables at the top level of the module scope without using eval() in a fairly big hack. Function scopes just don't work that way in Javascript.
You could also have the module assign things to the global object where they can be used without a prefix, but this is NOT a recommended practice in any way. The whole point of node.js modules is to avoid using any globals and to make code entirely self contained with little chance of global collisions.
Or, you could have your module export a giant string of Javascript and then eval() it inside of app.js in order to define new variables in the module scope. Again - not recommended.
Your best best is do things the "node.js way" and put everything on an object and export that object. Here's one variation:
app.js
var test = require("./module.js")();
test.fn(); // "executing fn"
test.fn2(); // "executing fn2"
console.log(test.myVar); // "test"
module.js
module.exports = function () {
return {
fn: function () {
console.log("executing fn");
},
fn2: function() {
console.loog("executing fn2");
},
myVar: "test"
}
};
You can do something like that using an IIFE. The method, when required, will automatically run and return an object, which you can then use in your application.
module.js:
global.test = (function() {
return {
fn: function() {
console.log("executing fn");
},
fn2: function() {
console.log("executing fn2");
},
variable: "test"
}
})();
app.js
require("./module.js"); //just include, no need for a wrapper variable
test.fn();
test.fn2();
console.log(test.variable);
Note that this technique will overwrite the global variable test if it already exists.
This answer should not encourage you to use global within your node.js modules (see jfriend00's comments above) as it makes your code vulnerable for name collisions with other modules and thus your modules less portable.
Within module.js you have access to the global object of node.js runtime environment.
module.js:
global.test = {
fn: function() {
//Do something
},
fn2: function() {
//Do something different
},
variable: "test variable"
}
app.js
require("./module.js"); //just include, no need for a wrapper variable
test.fn();
test.fn2();
console.log(test.variable);
Note that this technique will overwrite the global variable test if it already exists.
I'm new to js and trying to understand global and private functions. I understand global and local variables. But if I have an html named test.html and a 2 js files named test1.js and test2.js. Now I include the test1.js and test2.js in test.html and call the functions written in test2.js inside test1.js and test.html.
The functions that I have written in test2.js are in this form
function abc(){...}
function pqr(){...} etc.
are these above functions global? If they are , how can I not make them global and still access them in test1.js and test.html?
As I have read global functions or global variables are bad right?
Everything in JS is bound to containing scope. Therefore, if you define a function directly in file, it will be bound to window object, i.e. it will be global.
To make it "private", you have to create an object, which will contain these functions. You are correct that littering global scope is bad, but you have to put something in global scope to be able to access it, JS libraries do the same and there is no other workaround. But think about what you put in global scope, a single object should be more than enough for your "library".
Example:
MyObject = {
abc: function(...) {...},
pqr: function(...) {...}
// other functions...
}
To call abc for somewhere, be it same file or another file:
MyObject.abc(...);
in test2.js you can write this to make the function global
window.abc = function(){...}
and then in test1.js yo can access it like this
window.parent.abc();
I hope it will help you
Anything defined in a file without any sort of wrapper will be bound to the window object. Anything bound to the window object is global.
Example:
//these are global variables
foo = 123;
var ABC = 'school';
//these are "private" variables
test = function(){
var foo = 123
}
(function(){
var ABC = 'school';
}).call(this);
Since global variables in every file will be part of the window object, you can access them between files. It is important when creating "private" variables you add var. This says override any global variables in the current "wrapper". If I have a global variable foo and I define it again in a function with var they will be separate.
var foo = 123;
(function(){
var foo = 987; //this foo is separate from the above foo
}).call(this);
If you do have a "wrapper" and you want to define a global function you can do it like this:
window.foo = 123;
(function(){
window.foo = 123;
}).call(this);
Both functions will do the same thing.
Personally, I prefer to put everything in a wrapper and only define global variables when I need them using window.
(function(){
//all code goes here
//define global variable
window.foo = 123;
})call(this);
var SomeName = function() {
var function1 = function (number) {
return number+1;
}
var anotherFunction = function (number) {
return number+2;
}
return {
function1: function (number) {
return function1(number);
},
function2: function (number) {
return anotherFunction(number);
}
}
}();
calling
console.log(SomeName.function1(1)); //logs 2
console.log(SomeName.function2(1)); //logs 3
A modern approach (2020) to using global data is by using a global object literal and define there all your needed logic.
const Website = {
foo () {
console.log('foo')
},
bar () {
console.log('bar')
}
}
document.addEventListener('DOMContentLoaded', () => {
Website.foo()
Website.bar()
})
If your code is more complex than a couple of lines you will need to separate your code into multiple files and with webpack you merge them together into one file.
import Foo from './js/Foo.js'
import Bar from './js/Bar.js'
// define here another object literal or setup document events.
// webpack will merge all this together into one file
<script src="js/webpack-merged.js"></script>
The reasons you don't want to import individual js files with html is described here. The jist of it is you will have poor performance, so you must bundle all your js.
If you don't understand why global variables are bad, then why are you trying to avoid them?
Global functions aren't necessarily bad. What's bad is state that anyone and anything and change.
In general since you're new to Javascript, it's fine to start out with global functions spread out across multiple javascript files that you include in your html file via script tags.
As you transition from beginner to intermediate, you will have to look into some "module" solution (I personally recommend RequireJS).
For now though, you can make do with a simpler module pattern:
var T1 = function() {
return < some module object >
})(); // notice the parenthesis
Google "Javascript module pattern".
Also see this answer.
vos fonctions ne sont pas global si vous faite l'erreur de les incorporé dans par exemple :
$( document ).ready(function() {
function myglobalfunction() { ... }
});
vous devez retirer
$( document ).ready(function() {
your functions are not global if you make the mistake of embedded them in for example:
$(document) .ready (function () {
function myglobalfunction () {
...
}
});
you must remove
$ (document) .ready (function () {