Using var to declare variables in Javascript - javascript

I'm struggling with (what I believe to be) a scoping issue. Here's a sample of my code:
$(document).ready(function() {
var counter = 0;
function scrollTweets() {
counter ++;
// rest of code
}
...
)}; // end of document ready
When I look up the variable counter in Chrome's Javascript console it returns "ReferencedError". However, when I remove var from the code above and type counter into the console, it returns the value. Why is this?
I think understanding this simple concept would allow me to tackle issues that seem to pop up during development. Is it just a scoping issue on Chrome's part? Am I needlessly wrapping everything in the $(document).ready "function"?

The var locks the variable counter into whatever the lexical scope is -- which means its available in the current block, method, whatever, and can be attached to closed-in scopes (ie. closures), like you are doing with scrollTweets. So counter is only available in the ready callback and anything that has a closure around it, which is why you can't access it from your console.
When you take the var away, counter is effectively global, which is why you can access it in that case.

When you don't use var to set the scope of the variable, it automatically becomes a global variable, inside the global scope. That's why it is visible in the Chrome console.
As a note, I'm by no means implying you should make the variable global. In fact that's almost always a bad idea! Capturing the variable in the context of the scope where it's used is the right thing to do. If the Chrome console can't handle that you just need a better debugger. Firebug for Javascript does a wonderful job at handling scope - even clojures!

Related

Why is var not deprecated?

Lately after ES6 released, many sources suggested that I use "const" and "let" instead of "var", and that I should stop using "var" in my JavaScript.
What I wonder is, if "var" has no advantage over "let" in all points of view, then why didn't they just fix var, or even deprecate "var" instead of letting them go along side each other?
Backwards compatibility.
You're right in saying there is no real advantage to using var over let - if you define them at the start of a function their meaning is basically identical.
You're right that there is no real reason to write new code using var (except maybe this, if relevant).
There are pages on the internet that are decades old though, and no one is going to rewrite them. There is nothing really to gain by removing var from the language. For languages like HTML and Javascript that are interpreted - backward compatability is absolutely mandatory.
That is also why they chose not to simply redefine var. Take the following example code;
// THIS IS AN EXAMPLE OF BAD CODE. DO NOT COPY AND PASTE THIS.
if (logic) {
var output = "true"
} else {
var output = "false"
}
console.log(output)
If var was changed to behave like let then the console.log would cause a reference error because of the scope difference.
I believe sometimes you need to redeclare a variable to write less code.
One example is this function that generates a unique id:
function makeUniqueId(takenIds) {
do {
var id = Number.parseInt(Math.random() * 10);
} while (takenIds.includes(id))
}
Which may be invoked like that
makeUniqueId([1,2,3,4,5,6,7])
Here I declare id variable simply inside do block and it get's "hoisted" to the function scope. That would cause an error if I used let, because while block wouldn't see the variable from the do block. Of course I could declate let before do..while, but that would create the same function scoped variable with extra line of code.
Another example is when you copypaste code to devtools console and every time variables get redeclared.
One more example. What if you want to keep your variable declarations close to their usages but still treat them as function globals? If you use let in this fashion, you'll get rather confusing expirience in dev tools (all those Block, Block scopes).
But var 'keeps' them together in one 'Local' list:
Everything has their own advantages and disadvantages using var const and let is dependent on their use cases.
var
Variable declarations are processed before the execution of the code.
The scope of a JavaScript variable declared with var is its current execution context.
The scope of a JavaScript variable declared outside the function is global.
let
The let statement allows you to create a variable with the scope limited to the block on which it is used.
const
const statement values can be assigned once and they cannot be reassigned. The scope of const statement works similar to let statements.
I hope you understand.

Why JavaScript file starts with (function (undefined)? [duplicate]

Have you ever taken a look under the hood at the jQuery 1.4 source code and noticed how it's encapsulated in the following way:
(function( window, undefined ) {
//All the JQuery code here
...
})(window);
I've read an article on JavaScript Namespacing and another one called "An Important Pair of Parens," so I know some about what's going on here.
But I've never seen this particular syntax before. What is that undefined doing there? And why does window need to be passed and then appear at the end again?
The undefined is a normal variable and can be changed simply with undefined = "new value";. So jQuery creates a local "undefined" variable that is REALLY undefined.
The window variable is made local for performance reasons. Because when JavaScript looks up a variable, it first goes through the local variables until it finds the variable name. When it's not found, JavaScript goes through the next scope etc. until it filters through the global variables. So if the window variable is made local, JavaScript can look it up quicker.
Further information: Speed Up Your JavaScript - Nicholas C. Zakas
Undefined
By declaring undefined as an argument but never passing a value to it ensures that it is always undefined, as it is simply a variable in the global scope that can be overwritten. This makes a === undefined a safe alternative to typeof a == 'undefined', which saves a few characters. It also makes the code more minifier-friendly, as undefined can be shortened to u for example, saving a few more characters.
Window
Passing window as an argument keeps a copy in the local scope, which affects performance: http://jsperf.com/short-scope. All accesses to window will now have to travel one level less up the scope chain. As with undefined, a local copy again allows for more aggressive minification.
Sidenote:
Though this may not have been the intention of the jQuery developers, passing in window allows the library to be more easily integrated in server-side Javascript environments, for example node.js - where there is no global window object. In such a situation, only one line needs to be changed to replace the window object with another one. In the case of jQuery, a mock window object can be created and passed in for the purpose of HTML scraping (a library such as jsdom can do this).
Others have explained undefined. undefined is like a global variable that can be redefined to any value. This technique is to prevent all undefined checks from breaking if someone wrote say, undefined = 10 somewhere. An argument that is never passed is guaranteed to be real undefined irrespective of the value of the variable undefined.
The reason to pass window can be illustrated with the following example.
(function() {
console.log(window);
...
...
...
var window = 10;
})();
What does the console log? The value of window object right? Wrong! 10? Wrong! It logs undefined. Javascript interpreter (or JIT compiler) rewrites it this way -
(function() {
var window; //and every other var in this function
console.log(window);
...
...
...
window = 10;
})();
However, if you get the window variable as an argument, there is no var and hence no surprises.
I don't know if jQuery is doing it, but if you are redefining window local variable anywhere in your function for whatever reason, it is a good idea to borrow it from global scope.
window is passed in like that just in case someone decides to redefine the window object in IE, I assume the same for undefined, in case it's re-assigned in some way later.
The top window in that script is just naming the argument "window", an argument that's more local that the global window reference and it what the code inside this closure will use. The window at the end is actually specifying what to pass for the first argument, in this case the current meaning of window...the hope is you haven't screwed up window before that happens.
This may be easier to think of by showing the most typical case used in jQuery, plugin .noConflict() handling, so for the majority of code you can still use $, even if it means something other than jQuery outside this scope:
(function($) {
//inside here, $ == jQuery, it was passed as the first argument
})(jQuery);
Tested with 1000000 iterations. This kind of localization had no effect in performance. Not even a single millisecond in 1000000 iterations. This is simply useless.

Reaching a variable from nested function in Javascript

Can somebody please explain me why the following code works?
function getLastName()
{
fullName.lastName = "World";
}
function writeName()
{
fullName = {};
fullName.firstName = "Hello";
getLastName();
document.write(fullName.firstName + " " + fullName.lastName);
}
writeName();
For some reason, getLastName() can reach local its enclosing method's local state. How can this work? And also should I utilize this feature of Javascript or it is considered as a bad practice? If it is a bad practice, could you please explain why?
You can see the actual code working here at http://jsbin.com/atituk/2/edit
You don't have any local variables, that would require using the var keyword. All your variables are global and can be accessed anywhere within window, which is not considered good practice at all.
You have not used the var keyword against fullName inside the writeName function, you are therefore taking it from the scope outside writeName. It continues up the chain until it reaches the outer most scope, at which point it creates a global.
Globals are, in general, bad practise as they are hard to keep track of and more likely to be overwritten by accident (e.g. in a race condition).
If you were using strict mode this would create an error instead of a global.
You are using all variables of yours as global variables. So all are recognized everywhere. In order to have a better understanding of variable scopes in Javascript have a look at this great example https://stackoverflow.com/a/500459/655316

Have Firebug break when a global variable x is defined

We have a very large JavaScript application, where after many months of coding there have inevitably sprung a couple scope slip ups where a variable is defined without using the var keyword in the following fashion:
function() {
x = 5; ...
}
instead of:
function() {
var x = 5; ...
}
This is happening somewhere - we're not sure where - and searching for the variable name in question is difficult, since it's a common word that appears 1000s of times in our source.
Is there a way to ask Firebug to break on the line that first creates a given global variable? To clarify, I would like to break at exactly the instant when window.x switches from undefined to a defined value, and to break statement.
I've tried creating a watch expression and hoped I could turn it into a breakpoint, but I can't seem to create watch expressions without some kind of context or scope.
If this isn't possible with Firebug, I'd be interested in anything that can accomplish this in Firefox in general.
Provided a few things
You know the name of the variable
You don't have a variable with that name in the global scope (declared outside functions), but only inside functions.
There are calls to the function that declares the variable.
this little script would do the trick:
<script type="text/javascript">
window.__defineSetter__("x", function(value) { console.trace(); });
x = 1;
</script>
You'll get a trace of the executed code before that assignment.
It may fail to report some situations, so take a look at JSLint. Load all your JS files right there and lint them.
Here's another solution that only works in Firefox because it uses the Firefox-specific watch method.
Put this piece of Javascript at the very top of your html page, just after the <head> tag:
<script>
window.watch('x', function() { debugger });
</script>
Note that watch works on any Javascript object (window is the global Javascript object).
Here's the solution I ended up using by modifying Ionut G. Stan's solution:
window.__defineSetter__("name", function(value) {
if (value=="div") {
debugger;
}
});
I used debugger instead of console.trace(), so I could stop and look at it mid-execution. With console.trace() I got a bazillion trace statements due to this line executing many times.
The leaky scope turned out to be buried in Dojo, where Dojo is setting that variable to the name of a processed element.
View your web page on the SeaMonkey browser (I use version 1.1.16) and look at the error console, you will see a message of this type for each assignment to an undeclared variable :
Warning: assignment to undeclared variable x
Source File: http://....js
Line: ##
In addition to debugging, I would advise to check your code with JSLint, which reports unexpected assignments in the global scope as errors.
There are several command-line bundles of jslint, such as jslint4java which can be used cross-platform in Ant build scripts.

Start and Stop a javascript refresh

I have a page that needs to be refreshed every 60 seconds. On this page I am using iBox to popup various items. My problem is that a meta refresh kills the popup which is not wanted. Please keep in mind I have zero to little experience with javascript so my solution may be fundamentally wrong.
The solution I came up with is to use javascript to do the refresh. When the page loads I will start the timer, when an ibox pops up I will clear the timer, when the ibox closes I will start the timer again.
I am setting this up by using a simple function.
function timedRefresh(timeoutPeriod){
var resetId = 0;
resetId=setTimeout("location.reload(true);",timeoutPeriod);
}
Then I call the function <body onload="timedRefresh(60000)">.
My problem is stemming from when I try to call clearTimeout(resetID). I am trying to call the method from the ibox script's hide function, but it doesnt actually clear out the timer. I think it may be a scope issue and I may need to do some sort of Object.clearTimeout(Object.resetID) but that is just a guess.
Do this:
function timedRefresh(timeoutPeriod){
window.resetId = 0; // make it clear it's global by prefixing "window."
window.resetId=setTimeout("location.reload(true);",timeoutPeriod);
}
Then from the relevant ibox function use window.resetId.
Seeing your comment I'll add something.
"window." will work when scripting within a browser, should you use JS somewhere else it probably won't work.
As long as you're on a webpage, however, window is the global object and the "window." prefix is IMO a good way to make it clear that certain variables are global; if you use it consistently, all the variables that don't have "window." in front of them are always local.
You should know, however, that it would also work if you simply used resetId without any prefix and without var because any variable that isn't declared with var is automatically scoped to window.
This short-ish guide will teach you most of what you need to know about variable visibility in Javascript, execution contexts and closures. It will send you on your way to become a deadly Javascript ninja.
You're right, the problem is the scope of the variable resetId. As you declare it in the function with the var keyword, it is local to this function, and thus does not exist outside of it.
Simply declare resetId outside of the function to make it global, and you'll be fine :
var resetId = 0;
function timedRefresh(timeoutPeriod){
resetId=setTimeout("location.reload(true);",timeoutPeriod);
}
I'd suggest making the content on the page, that needs to be refreshed, updated through ajax. Here is a link to a tutorial http://www.w3schools.com/Ajax/Default.Asp
The easiest way is to add the resetId variable to the global scope:
var resetId = 0;
function timedRefresh(timeoutPeriod){
resetId=setTimeout("location.reload(true);",timeoutPeriod);
}
Alternatively, you might be able to define the iBox's hide function in the same scope, but I'm not too sure how iBox works.
More reading on scopes: http://javascript.about.com/library/bltut07.htm

Categories

Resources