I have a function with lots of variables and very big arrays being defined; this makes the function very large and hard to work with. How can I define the variables/arrays in another file and use them in this function?
Example:
DoStuff.js:
function genList(){
var listData = [
//lots of inner arrays and data
]
var dataItem = "value";//50 of these
//do stuff with the data
}
What I'm trying to do:
ExternalData.js:
var listData = [
//lots of inner arrays and data
]
var dataItem = "value";//50 of these
DoStuff.js:
function genList(){
//call variables/arrays from ExternalData.js
//do stuff
}
Note:
JQuery is applicable here, but I'd rather not call any other libraries for something so small.
I would define all the variables in an object for example:
var obj = {
array_one: ['x', 'y'],
some_value: 'z'
}
This method has the advantage of make a kind of namespace for all the variables, saving you from overriding values.
And then use that object into my code using some kind of include method.
One simple method could be to add the script before the one you are writing like this:
<script type="text/javascript" scr="file_with_object.js"></script>
Other more sophisticated but only advisable if you are going to repeat this kind of behavior
is to use a Library or a framework to make includes more concise, require.js is a good example
EDIT: In the previous example I used the object with var considering that the code was written on the global scope, I think it would be better to use window.obj = {} to ensure the variable is global. And, just for the record, any variable you define like this window.somevariable is going to be a global variable. Once you define a global variable you could use it anywhere in your code (after the definition takes place). The namespace is the right way to go though.
EDIT 2: I think this post is more about scope than includes. When you declare a variable this way: var some_variable; you are saying that you want to bind that variable to the current scope. So if you do that inside a function, that variable "lives" inside that function:
var some_var = 10;
function(){
var some_var = 5;
console.log(some_var) // 5
}
console.log(some_var) // 10
But if you declare the variable without the var on both cases you are making that varaible global the first time and overriding its value on the second:
some_var = 10;
function(){
some_var = 5;
console.log(some_var) // 5
}
console.log(some_var) // 5
And alway you declare a varaible without the var, that variable is accessible trough window.variablename, because you are not binding the variable to any particular scope, so the binding is made to the window objecy, which is the global scope "namespace".
Related
This may be very simple but i lost my way in finding the answer,
I have a named function inside a Backbone view. I'm trying to write unit test for this named function and i could see a variable is being declared in function scope. The state of this variable changes based on certain scenarios.
I have instantiated the view object inside my test suite and when i do a console.log(viewObject.namedFunction) i see the entire function being logged properly. Now how do i access the variable inside the namedFunction, i was expecting something like viewObject.namedFunction.variableName but it will not work and when i did that, it was not working as expected.
If the variable is tied to viewObject scope then it would have been easy to access it. But in this scenario it is not so can some one please help me in getting a hold on the variable inside named function in view object from test suite.
I think I understand your confusion, because when you define a variable using var in the window scope, it becomes a property on the window object... It would seem to follow that when you define a variable in a child scope, it should become a member of the local context, right? Nope. Globals are special ;-)
In fact, if that were the case, there would be no privacy!
If you want sign to be public, be explicit.
obj = {
namedFunction : function myself() {
console.log(myself);
myself.sign = 23;
}
};
obj.namedFunction.sign;
The only problem with this approach is that you can now assign a new value to sign from anywhere. The classic and preferred approach to this problem is to create a getter function for your private variable.
var obj = {
namedFunction : function myself() {
var sign = 3;
myself.getSign = function(){return sign;};
}
};
obj.namedFunction.getSign();
This isn't by any means the only approach, but I hope it was helpful.
One way to do this is like such:
namedFunction = (function(){
var theActualFunction = function(){
//Do something
//Access variable like: theActualFunction.MyVariable
};
theActualFunction.MyVariable = "value";
return theActualFunction;
}());
I have the following javascript method:
function 123_test_function(){
}
The function is generated by java and sent to the client. The 123 is the id of the component so it could change. i.e I can have another function called 111_test_function()
I want to pass this function as a reference.
So I need to create the reference
var 123_test_function = function 123_test_function(){
}
In another js file inside an object I have a function that needs to use the 123_test_function reference like so:
useFunction(123_test_function);
The problem I'm having is which the 123 part of the function.
In this object I have a variable(uniqueID) which has the number at the beginning of the function.
I need the function call to be something like:
useFunction(uniqueID+"_test_function");
This doesn't seem to pass a function instead it passes a string.
Am I doing something wrong?
For one, identifiers (such as function names) cannot begin with a digit.
To solve your problem, use an object, like this:
// 1. define an object to hold all your functions
var allFunctions = {};
// 2. store any function with a unique string as the ID
allFunctions['123_test_function'] = function () {
// whatever
};
// 3. call the function
allFunctions['123_test_function']();
allFunctions[uniqueID + '_test_function']();
Objects are associative arrays. They store key/values pairs, so they do exactly what you want here.
Note that functions don't need a name in JavaScript, so I did not use on in step 2.
If the function is defined as global one, it will be a member of global object (window in case of browsers). Hence you can just do window['id_'+uniqueID+'_test_function'] to access your function
useFunction(window['id_'+uniqueID+'_test_function'])
(Identifiers cannot begin with numbers in JavaScript so I added the 'id_' prefix. You can of course change it to your liking.)
function test_function(number){
if(number == 1)
{
return function() {}
}
if(number == 2)
{
return function() {}
}
}
call the function like this
var func = test_function(1)
func();
As a couple of people have correctly pointed out, a function (or indeed variable) name cannot begin with a numeric. Also this syntax is wrong:
var 123_test_function = function 123_test_function(){
}
The correct syntax would be:
var 123_test_function = function() {
};
...although it should also be noted that the effect of this is exactly the same as a "traditional"
function 123_test_function() {
}
...declaration, in the context of the window object - since window is effectively the global scope of a JS environment in a browser, it doesn't matter how you define the functions, they will always be accessible from anywhere. Understanding exactly what each method of declaring a function means in Javascript is important - luckily, Douglas Crockford to the rescue once again...
People have suggested various methods for calling your named functions from the context of a string, which is basically attempting to use "variable variable" syntax, a subject that has been discussed on SO and elsewhere at length. The eval() approach should be avoided wherever possible - if you find yourself needing an eval() chances are you went wrong somewhere a while back. #Tomalak has the right idea with a collection of functions held in an object, but this still needs the slightly messy string approach to reference things that are actually being accessed by a numeric ID. The collection approach has the advantage of not cluttering up the window object with what are likely to be single/zero use members.
But the way I see it, all you actually need here is an indexed array of functions, where all you need is the numeric index in order to access them. I suggest you create your functions like this:
// Do this once at the top of your JS
var test_functions = [];
// Now, for each function you define:
test_functions[123] = function() {
// Do stuff here
};
// And when you need to call the functions:
var funcId = 123;
test_functions[funcId]();
To keep the global namespace clean, my JavaScript code is wrapped like this:
(function() {
/* my code */
})();
Now I have some variables declared in this scope which I want to access using a variable variable name (e.g. the name is 'something' + someVar).
In the global scope I'd simply use window['varname'], but obviously that doesn't work.
Is there a good way to do what I want? If not I could simply put those variables inside an object to use the array notation...
Note: eval('varname') is not an acceptable solution. So please don't suggest that.
This is a good question because this doesn't point to the anonymous function, otherwise you would obviously just use this['something'+someVar]. Even using the deprecated arguments.callee doesn't work here because the internal variables aren't properties of the function. I think you will have to do exactly what you described by creating either a holder object...
(function() {
var holder = { something1: 'one', something2: 2, something3: 'three' };
for (var i = 1; i <= 3; i++) {
console.log(holder['something'+i]);
}
})();
(function(globals) {
/* do something */
globals[varname] = yourvar;
})(yourglobals);
evil solution/hack: Put the variable you need in a helper object obj and avoid having to change current uses to dot notation by using use with(obj){ your current code... }
I am really confused as to why sometimes vars will not work when "var" is declared in front of them when used in a namespaced object. Isn't adding "var" in front of every variable the correct thing to do to keep it outside the global namespace?
Or would creating any var without declaring "var" first in my namespaced object, ensure of this, so I don't eed to worry about "var"?
Here's an example of my code:
MYNAME.DoStuff = {
initialize: function() {
var var1 = 'name'; //1
var2 = 'name'; //2
this.var3 = 'name'; //3
var $var4 = $('#' + name); //4
$var5 = $('#' + name); //5
this.$var6 = $('#' + name); //6
},
linkStuff: function() {
// then use the vars from the init above in here
}
}
MYNAME.DoStuff.initialize();
Can someone tell me which number (1, 2, or 3) is correct? Are there cases where I would use more than one or all? How about when I need to do DOM references with jQuery? Which way is correct (4, 5, or 6)?
The var statement will bind the variable to the scope of the current function, in your example var1 is accessible only within initialize.
Your second example, var2 = 'name'; is simply an assignment made to a -possibly- undeclared identifier.
This is an anti-pattern, and should be avoided. If the identifier is not resolvable higher in the scope chain, var2 will end up being a property of the global object -an implied global, since most of the time you actually try to avoid globals-.
Moreover, the new ECMAScript 5 Strict Mode, completely disallows this kind of assignments, please avoid them...
The third example, this.var3 will create a property in the current object, in your example the this value of initialize will refer to MYNAME.DoStuff because you invoke the initialize method by MYNAME.DoStuff.initialize();.
In this third example you can access this kind of properties on your linkStuff function, just by this.var3 - if you invoke that linkStuff function properly, e.g. MYNAME.DoStuff.linkStuff();-.
Based on what it looks like you're trying to do in the linkStuff method, you might try this:
var DoStuff = {
firstVar: null,
secondVar: null,
initialize: function() {
// set initial values
this.firstVar = 'name';
this.secondVar = 'name2';
},
linkStuff: function() {
alert(this.firstVar); // 'name'
}
};
var myname = DoStuff;
myname.initialize();
myname.linkStuff();
As #CMS pointed out, var sets up a variable in the current scope. That's why you do var variablename outside of functions to create globals and var variablename inside functions to create locals.
But in the context of objects, there's more going on. Javascript has a feature called closures, which enables very powerful tricks like private, public and privileged methods (I don't normally like linking to Crockford because he's a bit of an arrogant knob, but sometimes he's a smart knob).
The other thing to watch out for is that Javascript objects are actually very different from objects in most other languages. In Javascript, you don't define them, you build them. If you do something like this:
function stuff() {
// Do init code here
this.linkStuff = function() {
// Do linkstuff code here
}
}
... you can do myname.dostuff = new stuff() and your initialization code will run automatically. That is also the point to fetch a jQuery object and assign it to a variable for later use.
I've heard from a variety of places that global variables are inherently nasty and evil, but when doing some non-object oriented Javascript, I can't see how to avoid them. Say I have a function which generates a number using a complex algorithm using random numbers and stuff, but I need to keep using that particular number in some other function which is a callback or something and so can't be part of the same function.
If the originally generated number is a local variable, it won't be accessible from, there. If the functions were object methods, I could make the number a property but they're not and it seems somewhat overcomplicated to change the whole program structure to do this. Is a global variable really so bad?
I think your best bet here may be to define a single global-scoped variable, and dumping your variables there:
var MyApp = {}; // Globally scoped object
function foo(){
MyApp.color = 'green';
}
function bar(){
alert(MyApp.color); // Alerts 'green'
}
No one should yell at you for doing something like the above.
To make a variable calculated in function A visible in function B, you have three choices:
make it a global,
make it an object property, or
pass it as a parameter when calling B from A.
If your program is fairly small then globals are not so bad. Otherwise I would consider using the third method:
function A()
{
var rand_num = calculate_random_number();
B(rand_num);
}
function B(r)
{
use_rand_num(r);
}
Consider using namespaces:
(function() {
var local_var = 'foo';
global_var = 'bar'; // this.global_var and window.global_var also work
function local_function() {}
global_function = function() {};
})();
Both local_function and global_function have access to all local and global variables.
Edit: Another common pattern:
var ns = (function() {
// local stuff
function foo() {}
function bar() {}
function baz() {} // this one stays invisible
// stuff visible in namespace object
return {
foo : foo,
bar : bar
};
})();
The returned properties can now be accessed via the namespace object, e.g. ns.foo, while still retaining access to local definitions.
What you're looking for is technically known as currying.
function getMyCallback(randomValue)
{
return function(otherParam)
{
return randomValue * otherParam //or whatever it is you are doing.
}
}
var myCallback = getMyCallBack(getRand())
alert(myCallBack(1));
alert(myCallBack(2));
The above isn't exactly a curried function but it achieves the result of maintaining an existing value without adding variables to the global namespace or requiring some other object repository for it.
I found this to be extremely helpful in relation to the original question:
Return the value you wish to use in functionOne, then call functionOne within functionTwo, then place the result into a fresh var and reference this new var within functionTwo. This should enable you to use the var declared in functionOne, within functionTwo.
function functionOne() {
var variableThree = 3;
return variableThree;
}
function functionTwo() {
var variableOne = 1;
var var3 = functionOne();
var result = var3 - variableOne;
console.log(variableOne);
console.log(var3);
console.log('functional result: ' + result);
}
functionTwo();
If another function needs to use a variable you pass it to the function as an argument.
Also global variables are not inherently nasty and evil. As long as they are used properly there is no problem with them.
If there's a chance that you will reuse this code, then I would probably make the effort to go with an object-oriented perspective. Using the global namespace can be dangerous -- you run the risk of hard to find bugs due to variable names that get reused. Typically I start by using an object-oriented approach for anything more than a simple callback so that I don't have to do the re-write thing. Any time that you have a group of related functions in javascript, I think, it's a candidate for an object-oriented approach.
Another approach is one that I picked up from a Douglas Crockford forum post(http://bytes.com/topic/javascript/answers/512361-array-objects). Here it is...
Douglas Crockford wrote:
Jul 15 '06
"If you want to retrieve objects by id, then you should use an object, not an
array. Since functions are also objects, you could store the members in the
function itself."
function objFacility(id, name, adr, city, state, zip) {
return objFacility[id] = {
id: id,
name: name,
adr: adr,
city: city,
state: state,
zip: zip
}
}
objFacility('wlevine', 'Levine', '23 Skid Row', 'Springfield', 'Il', 10010);
"The object can be obtained with"
objFacility.wlevine
The objects properties are now accessable from within any other function.
I don't know specifics of your issue, but if the function needs the value then it can be a parameter passed through the call.
Globals are considered bad because globals state and multiple modifiers can create hard to follow code and strange errors. To many actors fiddling with something can create chaos.
You can completely control the execution of javascript functions (and pass variables between them) using custom jQuery events....I was told that this wasn't possible all over these forums, but I got something working that does exactly that (even using an ajax call).
Here's the answer (IMPORTANT: it's not the checked answer but rather the answer by me "Emile"):
How to get a variable returned across multiple functions - Javascript/jQuery