I apologize in advance, this might have been discussed on StackOverflow before, I just do not know what this is called, so I could not find a satisfactory answer.
However, I am learning JavaScript and with a book called "Eloquent JavaScript". There I found the following piece of code, which repeatedly prompts the user to enter his name until he did it.
while (!input) {
var input = prompt("Who are you?");
}
I simply do not understand why this actually works instead of raising an error. At the time the condition expression is being evaluated, there is no variable called input out there. If I understand it right, there is no evaluation possible, which would normally prevent further execution. The statement in the while loop's body, which then creates a variable called input, is still being executed, though.
However, this made me anxious, so I tried this:
while (!bool) {
console.log("Hi");
var bool = true;
}
This is even weirder. It's same problem when it comes to the condition expression: bool is being created within the scope of the loop's body, after the evaluation of the condition. And secondly, bool is constantly set to be true, but still the code is being executed once, in other words, Hi is being printed once.
I am confused and would appreciate some help. ;)
This is one of Javascript's little eccentricities. The key thing to remember is that, in Javascript, variables are not necessarily created at the point in the code where var x = appears. They are always created at the top of the scope. This means at the beginning of the function that contains them, or the top of the global scope if that's the scope we're working in. This is called hoisting.
So your code may look like this:
function doStuff() {
while (!bool) {
console.log("Hi");
var bool = true;
}
}
But it will run like this:
function doStuff() {
var bool = undefined;
while (!bool) {
console.log("Hi");
bool = true;
}
}
(Remember that there is no such thing as block scope in Javascript.)
The first time, bool is undefined. !undefined is true, so the conditional passes. After that, bool is true, so the conditional fails. It is a similar story with input in your first example.
The variable will always be created at the very top of the scope, no matter where it is declared. For this reason, it is sometimes recommended as good practice to declare your variables at the top of the scope, since that is where Javascript will consider them to be. This prevents surprises like the one you cite.
JavaScript does not need a variable to be declared explicitly - you can access or assign a value to the variable in before you declare it explicitly. (It has more to it, as lonesomeday has explained - I just wanted to put it simply).
When you access the variable before declaring it explicitly, it would have the value undefined.
So, in your code, try using an alert(input); before the while if you want to see it yourself.
JavaScript has the unusual property that variables are scoped at the level of the function in which they are declared, not within their enclosing block (as is the case in languages like C++ and Java). This means that a variable declared within a function is in scope the instant the function begins executing, regardless of where within the body of the function the variable is declared. This behavior is sometimes referred to as "hoisting" or "lifting".
Many JavaScript programmers consider it a good practice to declare all the variables within a function at the very beginning of the function, just to avoid the strange property of having a variable in scope before it is declared.
An even more unfortunate behavior of JavaScript is that allows one to define global variables on-the-fly simply by setting them. So, if your program has no variable named input, then this code:
input = prompt("Who are you?");
Creates a global variable named input and assigns it the string returned by the prompt method. This can lead to all sorts of hard-to-debug side-effects and so is considered poor practice.
There are 2 bits to realize. Initially, input is undefined, which is a "falsy" value, so !input evaluates to true. The second thing to realize is once the var input or var bool are assigned, they are valid at the same scope as the loop (ie just outside it), so when the loop iterates a second time the variable will be set. For the input case, anything null or undefined is considered falsy, so once the input has a value the loop will exit. You can kind of see this in this bit of code:
while(!bar) {
console.log('1', bar);
var bar = true;
console.log('2', bar);
}
console.log('3', bar);
Related
I'm learning JavaScript, yesterday I think I should revise some basic knowledge, so I chose "function" topic. When I read this document from Mozilla, I saw this:
Note: Some JavaScript engines, not including SpiderMonkey, incorrectly treat any function expression with a name as a function definition. This would lead to zero being defined, even with the always-false if condition. A safer way to define functions conditionally is to define the function anonymously and assign it to a variable:
if (0) {
var zero = function() {
document.writeln("This is zero.");
}
}
So my question is, because it said a safer way, that's mean this way is not safe: What problem could be?
Thank you.
When you declare a variable using var it's hoisted to the top of the scope. So it would be possible for you to write some code like this:
if (someCondition) {
var zero = function zero() {
// do stuff
};
}
if (zero) {
zero();
}
When executed correctly, zero will always be undefined if someCondition is false.
If an engine incorrectly uses the named function expression as a function definition then it will be hoisted as well, meaning that zero will be a function before someCondition is even checked. This means that zero will have a "truthy" value no matter what someCondition is.
Basically, any time you would expect a value to be undefined because you haven't actually assigned a named function to it, it would actually be assigned to a function assuming you named that function the same thing as your variable.
I am doing the Udemy course Javascript: Understanding the Weird Parts right now, and I just learned about the creation phase and the execution phase that occurs when the interpreter interprets the JS.
I have a question, but I will first show you the code I am playing with:
http://codepen.io/rsf/pen/bEgpNY
b();
function b () {
console.log(a);
}
var a = 'peas';
b();
If I understand correctly, in the creation phase, the variables and functions are 'set', meaning they are given spots in memory. The variables are all given the placeholder value of undefined. Then in the execution phase, the engine executes the lines starting at the top. When b() is first called, 'a' still has the placeholder value of undefined, then 'a' is given its initial value of 'peas', b() is called again and this time 'a' has the value of 'peas'.
In my mind, one of two things has to be happening here. Alternative 1: In the creation phase, all variables are set before functions. This means that when a memory space for the function b() is created, the function includes a's value of undefined (because the 'a' memory space was already created with the value of 'undefined'). Alternative 2: the functions and variables are set in the lexical order they are in (in this case, b is created before a), and when b is created, the 'a' reference somehow means that the function is listening for any possible creation of an 'a' memory location, and when later the 'a' location is actually created, the reference refers to that spot.
Am I on the right track with either of these scenarios?
You can think of it like this.
Your original code:
b();
function b () {
console.log(a);
}
var a = 'peas';
b();
is actually executed like this:
var a;
function b () {
console.log(a);
}
b(); // log undefined because a doesn't have a value yet
a = 'peas';
b(); // log peas because a has a value
Basically all the variable and function definitions are hoisted at the top of the enclosing scope.
The order doesn't really matter because the code inside the b function doesn't get executed until you actually call the function.
If I understand correctly, in the creation phase, the variables and functions are 'set', meaning they are given spots in memory.
I would not use the term set for this--it usually is used to refer to a variable being set to (assigned) a particular value. I also would not use the term "spot" or "memory"--we don't need to worry about these internals. It's clearer just to say declared.
I also don't really like the use of the term "creation phase", which is both non-standard and confusing--what is being created, exactly? I would prefer the term "compilation".
The variables are all given the placeholder value of undefined.
To be precise, I would not say they "have the value of undefined", but rather "have no value", or "are not defined". undefined is not a value held by a variable which has not been assigned to yet; rather it's a state, which causes the variable to evaluate to the undefined value when accessed.
Alternative 1: In the creation phase, all variables are set before functions.
Yes, although again it's going to be confusing to use the word "set". Say, "all variables are declared before functions". This is the process of hoisting.
Alternative 2: the functions and variables are set in the lexical order they are in (in this case, b is created before a), and when b is created, the 'a' reference somehow means that the function is listening for any possible creation of an 'a' memory location, and when later the 'a' location is actually created, the reference refers to that spot.
No. The function does not "listen" to anything. It just executes when you tell it to.
Is this important?
Not really. It falls into the category of arcana. So we clog up our brains with rules like, variables hoist this way, function declarations hoist some other way, let has yet some other hoisting behavior. In practice, almost all style guides will call for you to declare variables at the top of the function, and linters will warn you if you don't (or can be configured to do so). This immediately eliminates all variable hoisting issues.
Some people like to put internal functions at the bottom of their function, and that works fine since, if it's a function declaration (ie function foo() { }) the whole thing (including the definition) is hoisted. If it's a function expression being assigned to a variable (ie var foo = function() { }), then it's a variable, and we already decided to put those at the top of our function--see paragraph above.
In general, if your program depends on hoisting behavior, it's written badly. If you need to understand hoisting behavior to understand how the program works, it's written badly.
To summarize, all you really need to learn is one rule: put variable declarations (and their initializations) at the top of your function. Then you don't have to worry about hoisting at all.
(There are some exceptions, such as declaring a variable inside a for statement, as in for (var i...), which is fine, assuming i is not being used for anything other than the index of the loop.)
For some reason, people learning JS seem sometimes to focus on these oddities--such as "why does " " == false or something. I would suggest instead focusing on the how to think about your problems, and break them down, and writing nice clean code that just works, and that you and other people can maintain without worrying about the arcana. I've been writing JS for many years, and cannot remember the last time I encountered a problem related to hoisting.
I have a function that looks like this:
function SomeFunction() {
var SomeVar;
if (SomeCondition) {
SomeVar = 4;
}
}
This is equivalent to:
function SomeFunction() {
if (SomeCondition) {
var SomeVar = 4;
}
}
Does using the var statement only if the condition is true make a difference or not, is there any best practice or performance implications concerning this?
Thanks.
Edit: yes, I am aware that there's no block scope, just function scope.
They function exactly the same, but there are two schools of thought about where to put it:
One group says you should put it at the top of the function, because that avoids the false impression you are relying on (nonexistent) block-scoping.
The other group says you should put it in the appropriate block, because that signals you intend to treat the variable as if it were block-scoped and not use it anywhere else.
As far as I know, I am the sole member of the second group.
Where the var statement is put has no effect on your code. This is purely a matter of style.
Some people feel that it's much clearer to put the var at the start of the function block. The lifetime of a variable in Javascript is tied to the function in which it's declared and not the scope. Many other curly brace languages do the opposite and this is a source of confusion for many new users. Hence people believe declaring at the start of the function leads to clearer code.
In JavaScript, there is no block scope for variables like in C/C++. Therefore, even if you declare your variable in the if () {} block, the variable is actually created immediately at the beginning of the function. This effect of "pulling declarations up" is usually called "hoisting".
Although both codes are correct, the first one is probably semantically better, as it emphasizes the fact that the variable exists regardless of whether SomeCondition is true.
Those are both actually equivalent. Read up on "hoisting" and "function and block scope".
As far as speed goes, you're better off using the second case - combining the declaration and assignment in the same statement. See: http://jsperf.com/stackoverflow-frenchie
Put it at the beginning of the function. It is always moved there anyway during the runtime, but it clears the confusion / untrue assumption if you put it where it is really executed.
So in you case, the first snippet.
(also, purely style, write identifier of everything except classes camelCase, not PascalCase)
I have a Sublimelinter installed in Sublime Text 2 and it's great. However it doesn't like the following code:
if(condition){
var result = 1;
}else{
var result = 2;
}
process(result);
It says for var result = 2; that result is already defined and for process(result); that it's used out of scope. Is it just mistaking the {} of the if statement for a more closed scope or should I really be doing it like this:
var result;
if(condition){
result = 1;
}else{
result = 2;
}
process(result);
No it is not "wrong"; it will get hoisted to the top of the nearest function definition, as per the ECMAScript specification.
Yes, your program "Sublimelinter" is incorrect to claim the variable is out of scope.
It is not wrong. If you get that error, you defined result earlier in your code.
You can also simplify your condition to this so you don't have to use result:
process( condition ? 1 : 2 );
Javascript doesn't have 'block-scoping' like many other languages. If it did, the variable result would not exist when you tried to call process(result) because it would not be possible to reference it outside of the {} block where it was defined.
However, javascript only has function scoping, where variables in one function cannot be accessed by another function. Where variables are declared in the function has no significance whatsoever, because it will still be accessible from anywhere inside that function (no block scope). Hence, both code snippets you posted are equivalence to whatever interpreter is running the code.
The second is preferable because it is clearer as it shows where the variable will be used (throughout the function). It also prevents the variable from being declared twice inside the scope of the function, which may not necessarily cause anything bad to happen, but it will definitely not cause anything beneficial. You should almost always declare a variable once at a higher level instead of twice at different lower levels, even though it doesn't really matter since the scope of the variable will be the entire function no matter where it is declared.
JavaScript does not have block scope. Variables are scoped to the function they are defined in, meaning that when you declare a variable inside of an if block, it is "hoisted" to the top of the function.
Since the variable is technically defined at the top of the function anyway, it is considered a best practice to move variable declarations to the top of the function so that the intent of the code is clear.
I'd say your code isn't "wrong" but it is misleading to people reading the code who aren't familiar with how scope works in JavaScript. I would definitely opt for the second version, because it actually reflects how the code is executed.
Here's a good article explaining variable hoisting.
Declare your var pointer once with-in the function you have your if statement at. Like ninjagecko mentioned all vars get sent to the top of their containing functions.
However; do be careful because if you declare the same var twice like you have it , it will reset the var.
I recommend doing this:
var result = MORE_LIKELY_OUTCOME;
if (LESS_LIKELY_CONDITION) {
result = LESS_LIKELY_OUTCOME;
}
process(result);
This way, you are setting result initially to what you are expecting it to be most of the times.
Then, the if statement will change result if the condition occurs.
It turns out that SublimeLinter is using JSHint which has the option to surpress this warning and explains why it exists.
funcscope This option suppresses warnings about declaring variables
inside of control structures while accessing them later from the
outside. Even though JavaScript has only two real scopes—global and
function—such practice leads to confusion among people new to the
language and hard-to-debug bugs. This is way, by default, JSHint warns
about variables that are used outside of their intended scope.
Just now,I saw some code like this:
if(condition){
var xx='sss';
}
//do something
if(condition){
console.info(xx);
}
Now, I just wonder why the second if statement work? How can it access the xx variable since it is a local variable defined in another if statement?
var in JavaScript is scoped to the containing execution context (e.g., the whole function's scope, or the whole global scope if the var is at global scope), not the block. JavaScript doesn't (yet) have block scope (ECMAScript6 looks likely to add it, via the new let keyword).
The code you've quoted is exactly equivalent to this:
var xx;
if(condition){
xx='sss';
}
//do something
if(condition){
console.info(xx);
}
This is covered by Section 10.5 of the specification, which describes what the engine does when entering a new execution context. (It's basically a two-phase process, first setting up all the declarations, and then executing step-by-step code.)
More: Poor misunderstood var
In JavaScript the scope is exacted to the closure (the last enclosing function block, or defaults to the window object). When a variable is declared anywhere within that function block it is hoisted to the top of the scope, so in essence a variable exists as undefined starting at the very top of the scope if it is declared anywhere in the scope.
Think of it like this, when the code begins executing it scans all the instructions for declarations and allocates the symbol name starting immediately.
console.log(x); // undefined
console.log(y); // error: Uncaught ReferenceError: y is not defined
var x;
for that matter you can take it to extremes:
console.log(x); // undefined, not an error
while (false) {
if (false) {
var x;
}
}
even though var x can't possibly be reached, and during execution would be optimized away completely. the engine will still hoist the variable to the top of the scope
hope this helps -ck
useful link: http://www.youtube.com/watch?v=taaEzHI9xyY&feature=youtu.be#t=42m57s
var declarations affect the entire scope of the smallest containing function or program. JavaScript is not block scoped.
Crock says:
Variable Declarations
All variables should be declared before used. JavaScript does not require this, but doing so makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals. Implied global variables should never be used.
The var statements should be the first statements in the function body.
It is preferred that each variable be given its own line and comment. They should be listed in alphabetical order.
var currentEntry; // currently selected table entry
var level; // indentation level
var size; // size of table
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
Use of global variables should be minimized. Implied global variables should never be used.
Note, this is changing with the let statement, and in current JavaScript (EcmaScript 5), the variable name in a catch block is block scoped.
javascript doesn't have block scope, so var xx='sss' is either locally scoped (if your sample code is inside a function) or globally scoped (if your sample code is not contained in a function).
JavaScript is a dynamic language, that isn't always picky about things like variable scoping. So, this "feature" allows you to write the code
if (condition) {
var xx = 'sss';
} else {
var xx = 'ttt';
}
// do something
if (condition) {
console.info(xx);
}
I would recommend avoiding this, since it makes your program harder to understanda and reason about.
If you declare a variable using var within a function, the variable is scoped to within that function. An if statement is not a function.
I'm assuming in this case both if statements are within the same function and therefore xx is in scope?
If a variable is declared inside a conditional statement, it is still available anywhere following the declaration in the containing function (or globally if the conditional is not in a function). However, it will equal undefined if the condition evaluates to false, unless the variable is later assigned a value.
If a local variable is referenced globally or in another function, a JavaScript error will occur. Depending on your browser, the error may say the variable "is not defined" or "is undefined". This is different from the variable equaling undefined like mentioned above, because a variable that equals undefined can still be referenced.