I have an oop function in javascript like this:
'use strict';
function oopFunc(){
this.oopMethod(){
console.log('hey it works');
}
}
function foo(){
var init = new oopFunc();
init.oopMethod();
}
function bar(){
var again = new oopFunc();
again.oopMethod();
}
how can I initalize the oopFunc object just once (like a global variable) and use the methods like this?:
'use strict';
function oopFunc(){
this.oopMethod(){
console.log('hey it works');
}
}
function initOopfunction(){
init = new oopFunc();
}
function foo(){
init.oopMethod();
}
function bar(){
init.oopMethod();
}
I have to pass variable parameters to the method but I dont want to initalize a new Object of it for each time I want to use it
EDIT
I need to initalize the function within a other function because the oop function get some parameters which must be typed in by the user
If you want to initialize the common object from a function (although I dont undestand why you want to do that), you can just declare the var in the common scope, and initialize it from somewhere else.
'use strict';
var myObj;
function ObjConstructor() {
this.hey = function () {alert ('hey');};
}
function init() {
myObj = new ObjConstructor();
}
function another() {
init(); // Common object initialized
myObj.hey();
}
another();
Check it here: http://jsfiddle.net/8eP6J/
The main point of 'use strict';, is that it prevents the creation of implicit globals when you don't declare a variable with var. If you declare the variable explicitly, you are good to go.
Take your time and read this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
Moreover, I would recommend you to wrap your code within a autoexecuted function not to pollute the global scope and avoid collisions with other scripts that might be running in the site. Ideally your whole application should live only in one global variable. And sometimes you can even avoid that. Something like the following:
(function () {
'use strict';
// the rest of your code
})();
Related
I have a couple of variables in my application that I have to use in most of my closures, like variables holding preloaded requests, or variables holding the current state of application (that need to be changed dynamically in different places).
So my application structure looks like this:
(function() {
var MainModule = (function () {
})();
var Utils = (function () {
})();
var Events = (function () {
})();
})();
And I create these variable inside MainModule, but want to change them, remove them, etc, inside Utils and Events. I've been thinking about two ways:
Creating Context closure that keeps an array of those variables, and have get() and set() access methods.
Passing these variables to closures as arguments, but I coulnd't unset them and I'd have difficulties because of the way javascript passes arrays/objects to functions.
How should I handle it?
(function() {
var MainModule = (function () {
var mine;
return {
getMine: function(){ return mine; },
setMine: function(a){ mine = a; }
}
})();
var Utils = (function () {
return function(module){
module.getMine();
}
})();
var Events = (function () {
})();
})();
IIFE does not give anything to put into the MainModule variable so I'm assuming something else will be calling something within Utils. get/set is the safest way to give access to private variables. Like the comments said, IIFE should only be used when needed, otherwise it's just pointless abstraction.
I have some functions inside of functions and I am having trouble retrieving a variable. It will be easier to show in code I want to log the var three in the testit function but not sure how to do so.
test();
function test(){
var abc;
function one(){
abc = 1;
two();
}
var three;
function two(){
console.log(abc);
three = 2;
testit();
}
one();
}
function testit(){
console.log(three);
two();
}
to make test an object you would do the following:
function test(){
this.abc = 0;
this.three = 0;
this.one();
}
test.prototype.one = function(){
this.abc = 1;
this.two();
}
test.prototype.two = function(){
console.log(this.abc);
this.three = 2;
}
test.prototype.testit = function(){
console.log(this.three);
this.two();
}
and run it like so:
testObj = new test();
testObj.testit();
hope this helps.
edit: BTW: if you put a call in function 'two' back to function 'testit' you'll end up with an infinite loop.
Here's an explanation of what's happening:
When you wrap code in a function, you get what's called function scope. This means that the scope within the function belongs to the function and not to a scope above or outside of it (whichever way you want to look at it).
A closure allows an expression (typically, a function, as MDN states) to have it's own scope while sharing the scope of it's outer or higher scope.
So, let's look at an example:
// This represents the global, or window, scope.
// Analogous to window.outer_var.
var outer_var = 'outer var';
function outer_func() {
// New scope! Local only to outer_func and those
// expressions (functions) *enclosed* by
// `outer_func(){...}, e.g. inner_func(){...}.
var inner_var = 'inner var';
// Only outer_func() or inner-enclosed (to
// inner_func()'s definition) functions can
// access inner_func().
function inner_func() {
// Another new scope! Can access inner_var
// and inner_func_var (below). outer_func()
// canNOT access inner_func_var, though.
var inner_func_var = 'inner func var';
}
}
outer_func(); // Of course, it's in scope and accessible.
inner_func(); // This will cause ReferenceError: inner_func is not defined error.
Simply as it is (no wrapping context, with a closure), var outer_var is created with the global or window scope. It may be accessed in all of the following:
console(window.outer_var);
function outer_func() {console.log(outer_var);}
function inner_func() {console.log(outer_var);} No matter where inner_func's defined.
Here, #2/3 are analogous to:
function outer_func() {console.log(window.outer_var);}
function inner_func() {console.log(window.outer_var);}
Or global this:
function outer_func() {console.log(this.outer_var);}
function inner_func() {console.log(this.outer_var);}
Now, inner_var is accessible from the following:
function outer_func() {console.log(inner_var);}
function inner_func() {console.log(outer_var);} Only from within outer_func().
inner_func() may also only be accessed within outer_func(), because it belongs to the outer_func() scope, and thus is not visible/accessible outside of outer_func()*.
Lastly, inner_func_var is only accessible by:
function inner_func() {console.log(inner_func_var);} Only within outer_func().
To access your three variable, you have three choices:
Make three globally accessible (globals are generally discouraged as they may easily introduce difficult to resolve bugs when one is overwritten by some other code).
Return three from your test() function. In this case the value is accessed, not the actual variable within the function.
Create a property as #logic8 demonstrates, so it may be accessed as a property of an object.
* This isn't entirely true. outer_func() could export a reference to the function out of scope with return inner_func;. This is a more advanced concept, though, and won't be addressed here in depth. Here is an example.
You have to put it in a global to do so:
test();
var three = false;
function test(){
[..]
}
function testit(){
console.log(three);
two();
}
when you declare a variable with var it becomes local to that scope. If you want to access three in both functions, you can either declare it without var (making it global - generally frowned upon for good reasons) or declare it outside of the two functions: var three;
The correct way to do this is by using the closure pattern in javascript. This wraps your javascript class in its own function so anything you declare within that file is only local to your code.
Using jQuery, this is easily accomplished like so:
(function($){
//your code goes here
})(jQuery);
People typically do it this way so their javascript only executes when the page is ready:
$(document).ready(function(){
//your code goes here
});
It's a bit more complicated without jQuery if you want to execute your code when the document is ready:
document.addEventListener('DOMContentLoaded', function(){
console.log('document is ready. I can sleep now');
});
With your code, it would look something like this:
$(document).ready(function(){
var test = function(){
//test code here
};
var one = function(){
//one code here
};
var two = function(){
//two code here
};
var three = function(){
//three code here
};
var testIt = function(){
//test code here
};
});
This way, you can safely access all of your functions from the others without polluting the global namespace.
For some strange reason, when calling a function that assigns this to thisObj, I get an error:
TypeError: thisObj is undefined
Here's what I've got:
function templateObject()
{
"use strict";
var thisObj = this;
function _loadBackgroundImages()
{
"use strict";
// something happens here
}
thisObj.initialise = function()
{
"use strict";
_loadBackgroundImages();
};
}
The function is then called using the instantiation like so:
var templateObj = templateObject();
templateObj.initialise();
Can't figure out why I get the error - any idea?
Use new:
var templateObj = new templateObject();
Calling function with new will pass newly created empty object as this to the function and then return it to templateObj.
When you call a function like you've done (i.e. not as a method of an object):
templateObject()
Then, if you’re in strict mode, this will be undefined inside that function.
As #mishik pointed out, it looks like you wanted templateObject to be a constructor function, and to use it as such, you need to call it with the new keyword before it:
var templateObj = new templateObject();
One style note: it's conventional in JavaScript to name functions intended to be used as constructors with an initial capital.
That might make mistakes like this marginally less likely, as it'd look odd to see a function with an initial capital called without new:
function TemplateObject() {
...
}
var templateObj = new TemplateObject();
What I have is something like that:
jQuery(function($) {
'use strict';
var App = {
init: function() {
App.startTool();
}
[...]
and when I try to call App.init(); from another file it say that App is not defined.
I'm trying to create some test with jasmine and I've the same error.
How can I go inside this "literal class", nested inside a simple function, from external files?
Javascript has function scope. This means that variables defined within a function are only visible within that function. To access this variable from outside the function, you'll need to either declare it outside the function, attach it to the window or some other global object directly, or return it as a value from the function.
Declaring outside:
var App;
jQuery(function($) {
'use strict';
App = {
init: function() {
App.startTool();
}
[...]
Attaching to the window or other global namespace:
jQuery(function($) {
'use strict';
window.App = { //or namespace.App where namespace can be another global variable.
init: function() {
App.startTool();
}
[...]
The way you're wrapping it you're not going to be able to return the value, but if it was a different function you could do this:
var App= (function() {
'use strict';
var App = {
init: function() {
App.startTool();
}
return App;
}())
A little more on function scope: Variables declared within a function cannot be seen from outside that function. Variables declared outside a function can be seen from inside a function. So if you want an object to be global, you need to declare it outside any function, or set it as a property on something that already has been declared outside the function. In a browser, the window object is global by default. Other environments like nodejs or rhino will have their own global objects.
Its important to understand how JS scope works because its the foundation behind a lot of the more powerful features of the language, particularly closures and the module pattern.
Some people have also mentioned the benefits of namespacing. This is a good point for this context. Having a single global variable for a library or application allows you to avoid conflicts with other libraries or scripts you might be using. You can then attach your other variables to that global namespace variable and reference them as properties of that object. So instead of calling App.init directly, call myProgram.App.init() for instance.
If it is not exposed as a global than you can not touch it.
You would have to put it into some namespace that is in the global scope.
jQuery(function($) {
'use strict';
var App = {
init: function() {
App.startTool();
}
}
if (!window.myNamespace) {
window.myNamespace = {};
}
myNamespace.App = App;
});
The fun thing here is it will not exist until document.ready, not sure why you would want it wrapped with ready. The init call should be called on ready. So you are doing to have race conditions on what widget registers first.
You need to make App globally available if you want to use it from outside the function:
jQuery(function($) {
'use strict';
// attach it to window instead of using var
window.App = {
init: function() {
App.startTool();
}
};
});
A couple of days ago I have learned on my own example how bad global variables and functions are. So apparently the best solution is NOT to use them, however sooner or later I will need to reuse my variables and functions over and over again.
So my question is: Can I reuse my functions and variables without declaring them globally? Can it be done?
For example, I want to reuse my alertBox function and my containsP variable couple of times:
DEMO: http://jsfiddle.net/ajmyZ/
//I am BAD GLOBAL FUNCTION inside var
//But I am reusable!!!
var alertBox = function () {
alert("Hey I am BAD function!!")
}
$(document).ready(function () {
//I am BAD GLOBAL var
//But I am reusable TOO!!!
var containsP = $("div p:first");
containsP.click(function () {
alert("Hi BAD var HERE!!");
});
$("p").eq(1).click(function () {
alertBox();
});
//I am the NICEST function here
//but I am NOT reusable :(
$("p").eq(2).click(function () {
alert("I am the NICEST function here!!");
});
});
I guess the simplest way to avoid clobbering the global object is just to create your own "application context". You can do that, by creating a self-invoking function which wraps your whole js-code within each file.
(function( win ) {
"use strict";
var still_global_but_only_in_this_anonymous_closure = true;
$(document).ready(function() {
// ...
// accessing the global object:
win.some_global_property = true;
});
}( this ));
Actually, you're already creating such a local context with your anonymous function you pass into .ready(). This is just the more explicit way. That self-invoking method, just calls itself with the global object as argument (where you still can explicitly access global variables). Furthermore, by invoking "use strict"; you're protected from accidently creating global variables alá "Ops_I_Forgot_The_Var_Statment = true;
The code you posted has no global variables. A variable declared inside of a function (in the case of your example, the anonymous document.ready handler) will never be global unless you make one of two mistakes:
forget the var keyword, making an implicit global
explicitly say window.myVar = ...;