In Python one can get a dictionary of all local and global variables in the current scope with the built-in functions locals() and globals(). Is there some equivalent way of doing this in Javascript? For instance, I would like to do something like the following:
var foo = function(){ alert('foo'); };
var bar = function(){ alert('bar'); };
var s = 'foo';
locals()[s](); // alerts 'foo'
Is this at all possible, or should I just be using a local object for the lookup?
locals() - No.
globals() - Yes.
window is a reference to the global scope, like globals() in python.
globals()["foo"]
is the same as:
window["foo"]
Well, I don't think that there is something like that in js. You can always use eval instead of locals(). Like this:
eval(s+"()");
You just have to know that actually function foo exists.
Edit:
Don't use eval:) Use:
var functionName="myFunctionName";
window[functionName]();
I seem to remember Brendan Eich commented on this in a recent podcast; if i recall correctly, it's not being considered, as it adds unreasonable restrictions to optimization. He compared it to the arguments local in that, while useful for varargs, its very existence removes the ability to guess at what a function will touch just by looking at its definition.
BTW: i believe JS did have support for accessing locals through the arguments local at one time - a quick search shows this has been deprecated though.
#e-bartek, I think that window[functionName] won't work if you in some closure, and the function name is local to that closure. For example:
function foo() {
var bar = function () {
alert('hello world');
};
var s = 'bar';
window[s](); // this won't work
}
In this case, s is 'bar', but the function 'bar' only exists inside the scope of the function 'foo'. It is not defined in the window scope.
Of course, this doesn't really answer the original question, I just wanted to chime in on this response. I don't believe there is a way to do what the original question asked.
#pkaeding
Yes, you're right. window[functionName]() doesn't work in this case, but eval does. If I needed something like this, I'd create my own object to keep those functions together.
var func = {};
func.bar = ...;
var s = "bar";
func[s]();
AFAIK, no. If you just want to check the existence of a given variable, you can do it by testing for it, something like this:
if (foo) foo();
Related
I know this is kind of a silly example-- but why does this code result in an error that bar is not defined. Wouldn't javascript look to see if bar was a property of "this" object. I know that adding this, fixes the problem-- but this tends to throw me off. In other programming languages (C#) for instance, this is usually redundant-- why does it need to be added in the code below?
var myObject = {
foo : function(){
alert(bar);
},
bar : "hello world"
};
myObject.foo();
http://jsfiddle.net/Mv86n/
Wouldn't javascript look to see if bar was a property of "this" object
No. It looks at what variables are in scope, not what properties are members of the current context.
Because, as you have demonstrated, JavaScript does not start variable lookups with this.
http://jibbering.com/faq/notes/closures/#clIdRes
http://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
What is the scope of variables in JavaScript?
Javascript has function scope, not object scope.
Only identifiers declared within the same function is in the local scope, everything else is accessed from the global scope.
It just doesn't work that way. It could have, but the language designers probably thought that that way would lead to inefficiencies, ambiguities and code that it hard to see what is going on.
I'll admit that I am also sometimes annoyed by the necessity of prepending "this." onto things, and even more annoyed that I am constantly having to say "var self = this;", but such is life in Javascript. You just have to accept it for what it is, and move on.
In javascript, the lookup priority is ancestor functions scopes (which can be nested, unlike in C++ and Java) from the nearest of the code beiing executed to the farthest.
On that trivial example, it looks like having an implicit this would make sense, but it would be much more complicated to specify and used with different levels of nested functions and object.
(function() {
var myVar = "dsjsh";
return {
myVar: "var",
myMethod: function() {
/* which */ myVar;
};
}
})()
Obviously, the language made the choice of simplicity (at least for this matter).
JavaScript doesn't exactly have a concept of classes or class scope; myObject should be thought of as a map, moreso than an object. For example, you could do this:
function foo() {
alert(this.bar);
}
var myObject = {
bar: "hello world"
};
myObject.foo = foo;
In this case, why should foo know about myObject when it's defined? When you call myObject.foo(), JavaScript passes in myObject as this (of course, JavaScript's scoping rules regarding this are kind of strange, so this isn't always what you think it is), and you can access myObject through this. If you just called foo(), this would be something different (in a browser, it would probably be window), and even accessing this.bar wouldn't work.
Think of it this way:
var myObject = {
foo : null,
bar : "hello world"
};
myObject.foo = function(){
alert(bar);
}
Now, what is bar supposed to refer to? As you can see more easily now, bar is not in scope.
In C#, methods belong to objects and it is known what attributes they have, which is why such a thing is possible. But in JavaScript, you don't have that knowledge, "methods" don't belong and attributes are dynamic, which makes such scoping rules unfeasible.
In Javascript, I have seen three different ways to define a function.
Conventional style:
function foo()
{
//do something
}
New Js Ninja Style
var foo = function(){
//do something
}
DOM specific style
window.foo = function(){
//do something
}
What question is,
What is the difference between the above three? And which one should I be using & why?
The first one is function declaration. It is hoisted (you could use it anywhere inside current scope).
The second one is a variable definition using anonymous function. Variable is hoisted, assignment stays in place. The function may not be used until the line where you assign it.
The third one is assigning a global method. Similar to the second one, although works with global object, which is not good.
Yet, you could think about the fourth alternative(named function expression):
var foo = function bar(){ //do something }
Here, bar will be available only inside itself, which is useful for recursion and not churning current scope with it.
You are selecting any approach based on your needs. I'd only vote against the second approach, as it makes function behave like a variable.
As soon as you mention both the second and the third option, I'd like to remind that polluting global object is considered bad practice. You'd better think about using self-executing anonymous functions to create separate scope, e.g.
(function(){
var t = 42; // window.t still does not exist after that
})();
I suppose you may find a more detailed article on JavaScript Scoping and Hoisting useful.
First, see Javascript: var functionName = function() {} vs function functionName() {}.
Then we get to the difference between var foo = and window.foo =.
The first is a locally scoped variable which is nice and lovely (unless it is done in the global scope). The second is a an explicit global, which has all the usual issues of globals (such as likelihood of conflicting with other code).
We have a lot of setup JS code that defines panels, buttons, etc that will be used in many other JS files.
Typically, we do something like:
grid.js
var myGrid = .....
combos.js
var myCombo = .....
Then, in our application code, we:
application.js
function blah() {
myGrid.someMethod()
}
someother.js
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
So, should we be using the var myGrid or is better to use window.myGrid
What's the difference?
A potentially important difference in functionality is that window.myGrid can be deleted, and var myGrid can not.
var test1 = 'value';
window.test2 = 'value';
console.log( delete window.test1 ); // false ( was not deleted )
console.log( delete window.test2 ); // true ( was deleted )
console.log( test1 ); // 'value' ( still accessible )
console.log( test2 ); // ReferenceError ( no longer exists )
I would suggest creating a namespace variable var App = {};
App.myGrid = ...
That way you can limit the pollution of the global namespace.
EDIT: Regarding the number of variables issue - 2 possible solutions come to mind:
You can further namespace them by type(Grids, Buttons, etc) or by relationship(ClientInfoSection, AddressSection, etc)
You encapsulate your methods in objects that get instantiated with the components you have
ex: you have
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
becomes:
var Foo = function(combo, grid) {
var myCombo = combo;//will be a private property
this.myGrid = grid;//will be a public property
this.foo = function() {//public method
myCombo.someMethod();
myGrid.someMethod();
}
}
App.myFoo = new Foo(someCombo, someGrid);
App.myFoo.foo();
this way you limit the amount of little objects and only expose what you need (namely the foo function)
PS: if you need to expose the internal components then add them to this inside the constructor function
One nice use of window.variable is that you can check it without having a javascript error. For example, if you have:
if (myVar) {
//do work
}
and myVar is not defined anywhere on the page, you will get a javascript error. However:
if (window.myVar) {
//do work
}
gives no error, and works as one would expect.
var myVar = 'test' and window.myVar = 'test' are roughly equivalent.
Aside from that, as other said, you should descend from one global object to avoid polluting the global namespace.
In global scope the two are in fact equivalent functionality-wise. In function scope, var is certainly preferable when the behaviour of closures is desired.
I would just use var all of the time: firstly, it's consistent with the usually preferred behaviour in closures (so it's easier to move your code into a closure if you decide to do so later), and secondly, it just feels more semantic to me to say that I'm creating a variable than attaching a property of the window. But it's mostly style at this point.
The general answer to the question would be to use var.
More specifically, always put your code in an Immediately Invoked Function Expression (IIFE):
(function(){
var foo,
bar;
...code...
})();
This keeps variables like foo and bar from polluting the global namespace. Then, when you explicitly want a variable to be on the global object (typically window) you can write:
window.foo = foo;
JavaScript has functional scope, and it's really good to take full advantage of it. You wouldn't want your app to break just because some other programmer did something silly like overwrote your timer handle.
In addition to other answers, worth noting is that if you don't use var inside a function while declaring a variable, it leaks into global scope automatically making it a property of window object (or global scope).
To expand on what Liviu said, use:
App = (function() {
var exports = {};
/* code goes here, attach to exports to create Public API */
return exports;
})();
By doing that you can hide some of your implementation specific code, which you may not want exposed by using var's inside. However, you can access anything attached to the exports object.
How can I set a Global Variable from within a function?
$(document).ready(function() {
var option = '';
$("[name=select_option_selected]").change(function() {
var option = $(this).val();
alert(option); // Example: Foo
});
alert(option); // Need it to alert Foo from the above change function
});
Declare it outside the scope of your jQuery onready
var option = '';
$(document).ready(function() {
$("[name=select_option_selected]").change(function() {
option = $(this).val();
alert(option); // Example: Foo
});
alert(option); //This will never be "Foo" since option isn't set until that select list changes
});
if you want to initialize this to the current selected value try this:
var option = "";
var $select_option_selected = null;
$(function() {
$select_option_selected = $("[name='select_option_selected']")
$select_option_selected.change(function() {
option = $(this).val();
});
option = $select_option_selected.val();
});
The Bad Way
As the other answers point out, it's not a good idea to create global variables. And as they point out, you can create a global variable by:
Declaring variable outside of all functions
Initializing your variable without the var keyword
Or, declaring it as a property of the window object: window.options = 'blah';
Using jQuery's Data() Method
But there is a better way of creating a globally accessible value using jQuery (and other libraries). In jQuery, use the data() method to store values associated with DOM elements:
// store 'blah' at document root
$(document).data('mysite.option', 'blah');
// retrieve value
alert($(document).data('mysite.option'));
Notice "mysite"... it is a good idea to namespace your data keys for the same reason it is good to namespace global variables in javascript.
$(document).ready(function() {
var option = '';
$("[name=select_option_selected]").change(function() {
option = $(this).val(); //no declaration of new variable, JavaScript goes to what encloses the function
alert(option); // Example: Foo
});
alert(option); // Need it to alert Foo from the above change function
});
Are you sure you want to? global variables are generally to be avoided. In the browser, window is the global object, so if you do window.option = ..., then option will be available globally.
I highly recommend naming a global variable something more unique than "option", to avoid clobbering existing stuff.
Another option, which I also don't recommend: leave off var
myvariable = 'foo';
If myvariable has never been delcared before, it will be declared as a property on window, making it global. This is generally considered to be (very) bad practice however.
You can use the window. prefix to access a global variable from within the scope of a function
window.option = ...;
Two approaches not mentioned by anybody else, applicable when you: 1. don't have access to the global LexicalEnvironment,10.2.3 and 2. are trying to write code that you wish to support systems wherein a direct reference to the global object15.1 (such as window in the HTML DOM, or GLOBAL in Node[1]) isn't guaranteed:
Make an indirect15.1.2.1.1 call to eval, by wrapping it in a superfluous PrimaryExpression, thus: (1,eval)(...) (the digit and comma operator are meaningless) … and then calling the result thereof. This forces the code to be run in the global execution context.10.4.2
We can then declare10.5 a new variable in the global lexical environment, as suggested above; or, for that matter, do anything else that we desire within that environment:
function global_define(ident, value){
(1,eval) ("var "+ident+"; (function(v){ "+ident+" = v })") (value) }
To be less round-about (and, to boot, avoid the FUD-ridden eval call), we can directly access the global object and set a property4.2 on it, which will then be available as a global variable elsewhere in our code.[2]
Instead of taking the eval approach above and gaining access to the global object via code we've written in the global context, it turns out we can access the global object as the this value10.4.3 within any function that is called with null:
var global = (function(){ return this }).call(null)
global[ident] = value
Phew.
Okay, more reading, for those of you who haven't fainted from specification links and eval calls, yet:
#kangax covers all of the bases quite thoroughly. Seriously, read that if you have any questions I haven't answered here (including those relating to the all-important idiosyncrasies browser support!)
Obviously, the relevant sections of the ECMAScript 5 specification itself, to get an idea for how things are intended to work in an ideal world. No, really though; I know that specifications are a scary idea, but the ES (“JavaScript”) specifications are one of the easiest-to-read and most comprehensible specs I've ever seen. They're truly excellent. Of immediate note, and in no particular order,
10.4, Establishing an Execution Context: Covers how ‘global code’ and ‘eval code’ are handled, specifically.
10.2, Lexical Environments: These describe “where variables are stored.” (The ‘Global Environment’ of interest is one of these.)
10.1, Types of Executable Code: Covers what ‘global code’ and ‘Program’s are.
15.1, The Global Object: Unfortunately, far less relevant than its title makes it sound. Still worth a skim.
[1]: The discussion in other answers, suggesting that exports in Node.js and other CommonJS-compliant systems is somehow related to the global object, about which this question asks, is misleading. In terms of system-design, one might be better suited to using their environment's module tools than poking around on the global object … but that's a discussion for another Stack Overflow post. (=
[2]: For those of you following along in the spec, it's harder to demonstrate that property-members of the global object are accessible as Identifier dereferences. Start with 10.2.1.2 Object Environment Records and 10.2.3 The Global Environment to understand how the global object is linked to an environment, then hop on over to 18.12.3, 18.12.2, and 18.12.1 in that order, collectively describing [[Get]] on the global object.
Nota bene: At no point in this elaboration did I suggest that doing either of these things was a good idea. Or, for that matter, that interacting with the global scope at all is a good idea. Of no relation to the question at hand, but proffered to soothe my own conscience, I add that I wrap all of my own code in a IIFE beginning immediately at the top of the file; this, along with religious application of the var keyword, ensures that I never interact with JavaScript's handling of the global object at all. A huge mess, avoided. You should do that. I said so. I'm smart. (;
just declare a global object
var obj={};
function my_function()
{
obj['newVariable'] = 'someValue';
}
in this way i achieved global variable.
http://jsfiddle.net/Kba5u/
var foo = 'bar';
function changeFooToBaz(){
foo = 'baz';
}
// changeFooToBaz();
console.log(foo); #=> 'bar'
Now, uncomment the call to changeFooToBaz:
var foo = 'bar';
function changeFooToBaz(){
foo = 'baz';
}
changeFooToBaz();
console.log(foo); #=> 'baz'
changeFooToBaz has indeed changed the contents of foo, a variable that was declared at a higher scope than the function.
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Below is demonstrating what I'm talking about.
I just need to get rid of eval.
//Used to determine where the variable is being stored
var variableScope = "global";
(function(window){
var variableScope = 'insideFunction',
appearingToBeGlobalFunction = function(){
alert("This Function appears Global but really isn't");
};
window["addFunction"]=function(funName,fun){
//window[funName] = fun; Doesn't work
eval("window[funName]="+fun+";");
}
})(window);
addFunction("alertTest",function(){
alert(variableScope);
appearingToBeGlobalFunction();
});
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
Edit: The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
You can't get rid of eval and still expect it to work. That's the only way to take a look at members of the scope after it's been "closed." I've messed around with something similar in the past, but I would never actually use it anywhere. Consider an alternate solution to whatever you're trying to accomplish.
eval("window[funName]="+fun+";");
Oh dear Lord.
The reason this “works” is that you are converting the function fun (alertTest) into a string to put it in the eval argument.
It happens that in most desktop browsers, a native JS function's toString() result will be a string that looks like a function expression containing the same code as the original declaration. You're turning a function back into a string and re-parsing that string in the context of the new enclosing function, so the new function value is the same code but with a different closure.
However, it is not required that Function#toString work like this, and in some cases it won't. It is not safe to rely on function decomposition; avoid.
You can certainly only do this kind of horrific hackery using eval, although there is no reason the window[funName]= part has to be inside the eval. window[funName]= eval('('+fun+')'); would work equally well (badly).
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Whyever would you do something crazy like that?
you could force the variables to be in the global scope eg instead of var variableScope = 'insideFunction' you use window.variableScope = 'insideFunction'
The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();