Accessing IIFE in Jasmine test - javascript

I have a JavaScript "class" that looks like this:
(function() {
'use strict';
function Calculator() {
this.currentValue = 0;
}
Calculator.prototype.add = true;
return Calculator;
}());
Now I am trying to test this with Jasmine – the CalculatorSpec.js looks like this:
(function() {
'use strict';
var calculator;
beforeEach(function() {
calculator = new Calculator();
});
describe('Calculator', function() {
it('should contain a function called "add"', function() {
expect(calculator.add).toBeTruthy();
});
});
})();
How am I supposed to access Calculator inside the Jasmine IIFE?
The files are included in the correct order in the specrunner, so I am sure it's a scope problem.
I already tried passing it to the IIFE as argument, but the problem is that Calculator is not available in global scope I guess.

You somehow have to make Calculator globally accessible to be able to test it. (And.. how would you otherwise use it in other code blocks?) The easiest way to do this by assigning the IIFE to a variable:
var Calculator = (function() {
'use strict';
function Calculator() {
this.currentValue = 0;
}
Calculator.prototype.add = true;
return Calculator;
}());

Related

Defining a class in JavaScript? [duplicate]

This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 4 years ago.
I was following a tutorial where they used a translator to translate a class in Typescript into javascript. The translated javascript is a bit confusing and I was wondering if someone can explain to me what the code is doing.
Original Typescript:
class Greeter {
greeting: string;
constructor(message: string){
this.greeting;
}
greet(){
return "Hello, " + this.greeting;
}
}
and the translated Javascript:
var Greeter = (function(){
function Greeter(message){
this.greeting = message;
}
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
return Greeter;
}());
I am confused about this part (function() { ... }());
what is the first () doing? why is the function(){} necessary? and what is the following () doing?
The syntax is pretty confusing and I hope someone can explain this.
I am confused about this part (function() { ... }());
IIFE this function will executed as soon as it is interpreted by the browser. You don't have to explicitly call this function.
what is the first () doing? why is the function(){} necessary?
All functions in javascript are Object by nature. To create a instance of it you have to call like new Greeter() so the context this is set properly. If executed like Greeter() now the context this is from where it's executed. In most cases it's the window object.
Reference articles
https://www.phpied.com/3-ways-to-define-a-javascript-class/
https://medium.com/tech-tajawal/javascript-classes-under-the-hood-6b26d2667677
That's called IIFE.
General syntax:
(function () {
statements
})();
But sometimes, you can write:
(function () {
statements
}());
I usually use the second's because it's following these steps:
Defining a function: function () { /* statements */ }
Calling the function: function () { /* statements */ }()
And wrapping the function: (function () { /* statements */ }())
Or use it with as an asynchronous thread:
(async function () {
// await some task...
})();
(async () => {
// await some task...
})();
You can also use it to define some local variable(s), like this:
let Person = (function () {
let _name = null;
class Person {
constructor(name) {
_name = name;
}
getName() {
return _name;
}
}
return Person;
}());
let person = new Person('Harry');
console.log(person.getName());
console.log(window._name);
For modules, you want to create some plugin(s) and make it to be global, you can write:
(function (global, factory) {
// we can use "global" as "window" object here...
// factory is a function, when we run it, it return "Person" class
// try to make it global:
global.Person = factory(); // same to: window.Person = factory();
}(window, function () {
class Person {};
return Person;
}));
This construct:
const foo = (function() { })();
Creates an anonymous function, and immediately calls it. The result gets places into foo.
It's possible to split this up in more lines with an extra variable:
const temp = function() { };
const foo = temp();
The reason typescript does this, is because placing code in function creates its own new scope. This makes it possible to do certain things without changing the global namespace.
(function() { ... }()); is a form of IIFE (Immediately Invoked Function Expression)
For example:
var Greeter = (function(){
return 1;
}());
The result is equal to
function fn() {
return 1;
}
var Greeter = fn();
The value of Greeter is 1 after executing the above codes. But the former one uses anonymous function and the latter one declared a variable fn to store the function.
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
This code snippet is to define a function on the prototype of object Greeter so that this function can be inherited when you create new Greeter(). You may refer to Object.prototype

Global function vs Angular-factory function - memory consumption when added to a global variable

I would like to understand the consequences of the following scenario:
var globalVar = {};
_v.func = function (event) {
function content...
};
WrappMainApp.factory('FactoryName', ['$rootScope', function ($rootScope) {
Some angular factory code...
var func = function (event) {
function content...
};
globalVar.func = func;
}
My question is, is it recommended - memory wise to add a factory function to a global variable, and when doing so, does the function reference carry the rest of the angular app references as well?

Is It Possible To Call A JavaScript Function Inside An Immediately-Invoked Function Expression

I'm using jQuery and have a function wrapped inside an immediately-invoked function expression like so:
<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
(function ($) {
var message = 'x called';
function x() {
alert(message);
}
})(jQuery);
x();
</script>
This will result is an error since the function "x" is not defined outside the immediately-invoked function expression. Is there any way to call the function "x" outside the immediately-invoked function expression?
Only if you expose the function in some way. For example, you can return it from the outer function:
var x = (function ($) {
var message = 'x called';
function x() {
alert(message);
}
return x;
})(jQuery);
x();
Or, similarly, you can return it on an object:
var obj = (function ($) {
var message = 'x called';
function x() {
alert(message);
}
return {"x": x};
})(jQuery);
obj.x();
Functions and variables declared inside of a function are not directly reachable from outside of that function, unless you provide some means of accessing them by returning something, or giving a reference to a variable declared outside of that function.
Make a namespace for other classes or functions you might want to do this with. You don't want to continually pollute the global namespace but there's no reason you can't make one namespace that's global and put your individual things underneath that:
(function($){
window.MyNamespace = function(){};
var message = "Something here";
$.extend(MyNamespace, {
x: function(){
alert(message);
}
});
})(jQuery)
MyNamespace.x()
You can change your code as follows:
<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
var x;
(function ($) {
var message = 'x called';
x = function () {
alert(message);
}
})(jQuery);
x();
</script>
jsFiddle link for this: http://jsfiddle.net/aLnbn/
Yes, ( one way is to: )just return it from the IIFE using a return statement, also you need to "catch" the return by assigning a variable to the IIFE
var foo = (function(){
return your_function;
}());
You can access your method by using your IIFE to return (or augment) a global variable.
You might do it like this:
var globalObject = (function (theObject, $) {
if (theObject.theMethod) {
return theObject;
}
var message = 'theMethod called';
theObject.theMethod = function () {
alert(message);
};
return theObject;
})(globalObject || {}, jQuery);
globalObject.theMethod();
The pattern we use is slightly better.
We have one global object (ie namespace) and we add modules to it by importing js files that contain IIFE's.
Each IIFE adds a new module to a single global object.
This makes it so our entire project has only one global object that can optionally utilize any of our modules by including a file.
I recommend checking out this article, which is a good discussion on the JavaScript module pattern:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
Try this:
var miFunc = (function($) {
var message = 'x called';
function x() {
console.log(message);
}
this.x = x;
return this;
})(jQuery);
miFunc.x();
Test: http://jsbin.com/erucix/2/edit
One of the purposes of a closure is to limit scope. That is why x() is defined and can be called inside of your immediately-invoked function expression but is undefined outside.
To have your code work without refactoring, you can take advantage of JS grammar which differentiates between a function statement and a function operator. Both are semantically identical but the latter can be assigned to a variable which works just right for your scenario:
var x; //scoped *outside* of the closure
(function ($) {
var message = 'x called';
x = function() {
alert(message);
}
})(jQuery);
x(); //alerts 'x called'
You can access your method by using your IIFE to return a global variable.
//IIFEs - Immediately Invoked Function Expressions
var namespaceTestIIFE = (function ($) {
/** Public functions and state. */
var pub = {};
$(document).ready(function () {
//your on ready logic
});
pub.testAlert = function () {
alert('Hello TestAlert');
}
return pub;
})(jQuery);
OR
var compareForm = (function ()
{
/** Public functions and state. */
var pub = {};
pub.testAlert = function () {
alert('Hello TestAlert');
}
return pub;
}());
To access function use "namespace.functionname" for example -
namespaceTestIIFE.testAlert();

Javascript namespacing - how to export functions and variables defined within a function scope based on their naming?

With the code below, other than specifying manually, is there a way to export only the functions and variables whose name doesn't start with an underscore?
var myapp = myapp || {};
myapp.utils = (function() {
var
CONSTANT_A = "FOO",
CONSTANT_B = "BAR";
function func() {}
function _privateFunc() {}
return {//return all variables and functions whose name does not have the "_" prefix.}
}());
Your idea requires being able to list all of the variables in the local scope. Unfortunately, JavaScript is not capable of doing that. See this related question.
There are two ways I've seen this be done:
1) Attach every variable when they're defined to an object to be exported:
var myapp = myapp || {};
myapp.utils = (function () {
var exports = {};
exports.CONSTANT_A = "FOO",
exports.CONSTANT_B = "BAR";
exports.func = function func() {}
function _privateFunc() {}
return exports;
}());
2) Or list all the exports at the end in an object literal:
var myapp = myapp || {};
myapp.utils = (function () {
var
CONSTANT_A = "FOO",
CONSTANT_B = "BAR";
function func() {}
function _privateFunc() {}
return {
CONSTANT_A: CONSTANT_A,
CONSTANT_B: CONSTANT_B,
func: func
};
}());
I've seen both (and even mixes of the two) used in practice. The second may seem more pedantic, but also allows a reader to look at a single segment of code and see the entire interface returned by that function.

Javascript : Best way to declare functions to be used globally?

My javascript file is getting pretty big (3000+ lines) and I'm getting confused as to how to layout my file and delare functions so that they can called anywhere in the file.
To summarise my JS file looks a little like this at the moment:
//ALL GLOBAL VARIABLES FIRST DECLARED HERE
var var1 , var2 ,var3
$(document).ready(function(){
//JQUERY STUFF
});
//ALL FUNCTIONS THAT NEED TO BE GLOBAL DECLARED HERE
function myFunction(){
//do some stuff here
}
I am running into problems with this as some functions I call in places don't seem to be declared at the time of calling or aren't available globaly. It's all very confusing now!
Could someone suggest the best way to layout a big js/jquery file with certain JS Functions, Objects and Variables available to be referenced anywhere in the file.
UPDATE:
So to simplify it this correct (see my comments)?
window.MainModule = (function($, win, doc, undefined) {//WHAT IS BEING PASSED IN HERE?
var foo, bar, modules; //VARIABLES ACCESSIBLE ANYWHERE
var modules["foobar"] = (function() {//WHAT IS A MODULE? WHEN WOULD I USE A SEPERATE MODULE?
var someFunction = function() { ... };//DECLARING MY FUNCTIONS?
...
return {
init: someFunction,//IS THIS WHERE I USE/BIND MY FUNCTIONS TO EVENTS AND ELEMENTS?
...
};
}());
// hoist a variable into global scope
window.Global = someLocal;
return {
init: function() {//FUNCTION TO INIT ALL MODULES?
for (var key in modules) {
modules[key].init();
}
}
};
}(jQuery, this, document));
The modules section isn't properly defined ... here's a slightly tidied up example.
window.MainModule = (function($, win, doc, undefined) {
var modules = {};
// -- Create as many modules as you need ...
modules["alerter"] = (function(){
var someFunction = function(){ alert('I alert first'); };
return {
init: someFunction
};
}());
modules["alerter2"] = (function(){
var someFunction = function(){ alert('I alert second'); };
return {
init: someFunction
};
}());
return {
init: function(){
for (var key in modules){
modules[key].init();
}
}
};
}(jQuery, this, document));
$(window.MainModule.init);
// We always use closures don't we?
window.MainModule = (function($, win, doc, undefined) {
var foo, bar, modules; // List of local variables.
var modules["foobar"] = (function() {
var someFunction = function() { ... };
...
return {
init: someFunction,
...
};
}());
// hoist a variable into global scope
window.Global = someLocal;
return {
init: function() {
for (var key in modules) {
modules[key].init();
}
}
};
}(jQuery, this, document));
// Let's kick off the MainModule on $.ready
// I recommend you do this in your `html` with page specific data.
$(window.MainModule.init);
[[Disclaimer]]: This is a pseudo-code module with some standard code excluded for brevity.
Anything declared with var x inside your main closure is available throughout the entire function. Of course it won't be set to what you expect it to be set unless you set it.
To control loading and flow split code into what's automatically executed in your self executing closure and what needs to manually inited by your controller with page/user specific parameters.
You can either declare them in Window scope:
window.variableName = myVariable;
or you can omit the var, which is the same as declaring something in window scope:
variableName = myVariable;

Categories

Resources