I have this function that populates the currsong variable with data.
The problem is that the variable currsong is only available inside the function and I need to access it globally.
// get a single audio url
echonest.artist(artist).audio( function(audioCollection) {
var currsong = audioCollection.data.audio[0].url;
return currsong;
});
Thank you!
To declare a global variable, you can always remove var:
currsong = audioCollection.data.audio[0].url;
I'm not sure if a global variable is a good solution for whatever you're trying to do, though. People suggest to avoid them for reason.
edit
An example.
Note, the variable will be undefined before function is executed first time. In your code, you only pass it into audio, you don't actually invoke it.
edit2
As Tgr notes, you can also declare global variable explicitly: window.currsong = .... There's no functional difference, but it improves code quality.
Scope is an interesting bird in javascript. So is closure.
Observation 1: you are returning a value from an inline function; that return value is meaningless.
Observation 2: by using the "var" keyword, you are specifying a local scope. Removing var will make the variable global. However, even if you do that it is possible that you will attempt to access that variable before the function gets triggered (i.e. it will be undefined).
Since you're just starting to wrap your head around the concept of closure and javascript scope, I'd recommend reading up on it and then rethinking your application design (since I would be willing to bet that you will learn something which prompts another approach).
In the mean time, try defining the variable outside of the inline function and giving it a temporary value. After that remove "var" from inside of the function.
// get a single audio url
var currsong = "temporary value";
echonest.artist(artist).audio( function(audioCollection) {
currsong = audioCollection.data.audio[0].url;
return currsong;
});
I've rewritten your code to make it a little more clear for myself and others. Please let me know if I've transliterated something incorrectly.
Basically, it looks like you're trying to get curSong as follows:
echonest.artist(artist).audio(
function(audioCollection){
var curSong = audioCollection.data.audio[0].url;
return curSong;
}
);
Right now, what you're doing is passing a function (the anonymous function defined by function(audioCollection)) to the audio function of whatever artist(artist) returns. As such, the curSong value is returned to audio(), and then only when audio() actually runs the function that its handed. I would look at audio() and try to see if there is a way to get curSong out of it. Otherwise, I'd do as slifty describes above and declare curSong in a larger scope, so that it can be accessed even outside of audio().
EDIT: For example, a sample audio function could be as follows:
function audio(inputFunction){
var audioCollection = getAudioCollection();
var song = inputFunction(audioCollection);
return song;
}
The variable curSong is in an anonymous function being passed to audio(). As such, it doesn't exist until that anonymous function is executed, as in the above code. Now, when you run your code (from the first snippet), the anonymous inner function will return curSong to audio(), and audio() will return curSong to you.
Related
When I call a function, a local scope is erected for that call. Is there any way to directly reference that scope as an object? Just like window is a reference for the global scope object.
Example:
function test(foo){
var bar=1
//Now, can I access the object containing foo, bar, arguments and anything
//else within the local scope like this:
magicIdentifier.bar
}
Alternately, does anyone have a complete list of what is in the local scope on top of custom variables?
Background: I'm trying to get down to a way of completely shifting to global scope from within a function call, the with statement is a joke, call works a little better, but it still breaks for anything declared in function scope but not in global scope, therefore I would declare these few cases in global scope, but that requires me to know what they are. The IE function execScript makes a complete shift, but that only solves the problem for IE.
Note: To anyone loading JavaScript dynamically, setTimeout(code,1) is a simple effective hack to achieve global scope, but it will not execute immediately.
No, there's no way to reference the variable object of the execution context of a function binding object of the variable environment of the execution context (that's what that thing is called [now; hence the strikethrough]; details in §10.3 of the specification). You can only access the limited view to it you get with arguments (which is very limited indeed).
Usually when I've wanted to do this, I've just put everything I wanted on an object and then used that (e.g., passed it into a function). Of course, any functions created within the context have access to everything in scope where they're created, as they "close over" the context; more: Closures are not complicated.
I know this is hugely late, and you're probably not even slightly interested any more, but I was interested in the feasibility of this too and you should be able to make a work around of some sort using:
(function(global) {
var testVar = 1;
global.scope = function(s) {
return eval(s);
}
})(this);
then running:
scope('testVar'); // 1
returns the variable from within the closure. Not particularly nice, but theoretically possible to wrap that in an object, perhaps using some validation and getters and setters if you needed?
Edit: Having re-read the question, I assume you'd want to access it without having to specify a function in the scope itself, so this probably isn't applicable. I'll leave this here anyway.
Certain versions of Netscape had a magic property in the arguments object that did what you're looking for. (I can't remember what it was called)
What about something like this?
<script type="text/javascript">
var test = {
bar : 1,
foo : function () {
alert(this.bar);
}
}
test.foo();
</script>
You don't need a keyword to reference a variable in the local scope, because it's the scope you're in.
Like this example:
var variable = '';
function myFunction(param){
variable = param;
alert(variable);
}
or like this:
function myFunction(param){
alert(param);
}
The only reason to do it the way you show in your first example is if you NEED to store the parameter persistently in a way that will survive from one invocation of the function to another. If you don't need that, then the second way is much, much cleaner and doesn't introduce unnecessary variables and doesn't pollute the higher scope.
I should add that arguments to functions work just like local variables. There is no reason to assign them to other variables just to use them. You can use the argument variable directly just fine.
I've recently read about closures in javascript and if I understand it correctly, it's when an inner function has access to variables in an an outer function. If so, under what use cases should I be using closures?
When you're thinking about writing a function, but realize that that function needs to do some internal state-keeping to determine its actions. The state should be stored, read and modified in a variable — but you don't want that variable existing outside of the function (if other functions can tamper with this function's state, things could go wrong), and at the same time you can't define the variable inside the function because each time you call it that variable would be reset.
A closure is effectively simply for locking variables in an immediate scope. The easiest example is probably a toggle:
var lightSwitch = ( function closure(){
var isLightOn = false;
return function flickLightSwitch(){
isLightOn = !isLightOn;
alert( isLightOn );
}
}() );
Imagine you're in a badly lit room, where you can't tell if the light is on or off except by flicking the switch to see the difference. When the code is executed, the closure function runs immediately, assigning the value false to isLightOn and assigning the function flickLightSwitch to the variable lightSwitch at the top. Now whenever the flickLightSwitch function is executed (called by the variable it's assigned to, lightSwitch), isLightOn becomes the opposite of whatever it used to be, and the user is alerted of its new value. External code can't read or modify the value of isLightOn because it's 'locked' in the closure function.
I'm new to JavaScript, and have a simple (I presume) question regarding best practices for accessing variables in functions:
When should I declare a global variable, as opposed to simple passing a value into a function?
Declaring a global variable should only be used as an option of last resort.
Global variables are bad in general and especially so in javascript. There is simply no way to prevent another piece of javascript from clobbering your global. The clobbering will happen silently and lead to runtime errors.
Take the following as an example.
// Your code
myParam = { prop: 42 };
function operateOnMyParam() {
console.log(myParam.prop);
}
Here i've declared 2 global variables
myParam
operateOnMyParam
This might work fine while testing your javascript in isolation. However what happens if after testing a user combines your javascript library with my javascript library that happens to have the following definitions
// My code
function myParam() {
console.log("...");
}
This also defines a global value named myParam which clashes with your myParam. Which one wins depends on the order in which the scripts were imported. But either way one of us is in trouble because one of our global objects is dead.
There are many, many reasons.. but an easy one is.. The argument of a function only exists in the function, while it's running. A global variable exists all the time, which means:
it takes up memory until you manually 'destroy' it
Every global variable name needs to be unique
If, within your function.. you call another function.. which ends up calling the first function, all of a sudden you may get unexpected results.
In short: because the function argument only lives for a really short time and does not exist outside the function, it's much easier to understand what's going on, and reduced the risk of bugs greatly.
When dealing with framework-less JavaScript I'll store my simple variables and functions in an object literal as to not clutter up the global namespace.
var myObject = {
variableA : "Foo",
variableB : "Bar",
functionA : function(){
//do something
//access local variables
this.variableA
}
}
//call functions and variables
myObject.variableA;
myObject.functionA();
i am wondering if i can do some cleanup routines that will auto grab timeouts / intervals. consider this:
var timeout = setInterval(function dimitar() {
console.log("hi!");
}, 1000);
console.log(window);
i had a look through window and can't find any reference to the function that's been passed on. the reference to timeout is there, sure enough. so where does the function 'live' here? is it launching a new instance of the js interpreter to eval/run/keep the code? how can you access it in relation to the timeout uid?
i know i can curry the setInterval function and get it to always store the reference into an array which i can then loop through and clear, but am curious if there's a natural way of doing this
The function you create in your example is using a named function expression. The name is only available within the function. Otherwise, it behaves the same as an anonymous function: you haven't assigned it to a variable and since it's not a function declaration, it doesn't create a dimitar variable in the enclosing scope. The following article may be useful: http://yura.thinkweb2.com/named-function-expressions/
There's no eval-type thing going on: you've just passed in a reference to a function into window.setInterval. This function cannot be retrieved afterwards unless you've assigned it to a variable previously, or it was a reference to a function defined by a function declaration.
If you want to keep a reference to the function around, it's simply a matter of storing it in a variable first:
var dimitar = function() {
console.log("hi!");
};
window.setInterval(dimitar, 1000);
so where does the function 'live' here?
The timeout/interval queue is an internal implementation detail that's not accessible to content JavaScript. It retains a reference to the function passed in to setInterval, but it's not a reference that's visible to you.
Incidentally you should generally avoid using named inline function expressions. Although it's probably OK in this example code, IE's JScript has some serious basic bugs with them that can trip you up if you're not careful. Stick to named function statements (function dimitar() { ... } ... setInterval(dimitar, 1000)) or anonymous inline function expressions (setInterval(function() { ... })).
is it launching a new instance of the js interpreter to eval/run/keep the code?
No, it's the same interpreter and the queue could even be implemented in JavaScript. But the variables behind it are hidden away from the caller.
how can you access it in relation to the timeout uid?
The timeout ID is by design completely opaque. The only defined interface that can do anything with it is the clearTimeout/clearInterval call. There is no interface provided to get the function back from a timeout ID.