In essence, I am trying to declare a variable in the condition-part of a while loop in javascript:
while (var b=a.pop()) {
do_sth(b)
}
Yet, my browser (firefox) doesn't accept that. Instead I have to go like so:
var b
while (b=a.pop()) {
do_sth(b)
}
which works. Is this behaviour expected?
Yes, it is.
If you want to, you can use a for loop, like this:
for (var b; b = a.pop(); ) { //Note the final semicolon
do_sth(b);
}
The question is a little dated, but I think the answers all miss an important distinction. That is, a while loop expects an expression that evaluates to a conditional, i.e., a boolean or value that can be converted to a boolean. See Mozilla docs for details.
A pure assignment (without instantiation) is coerced to a boolean via its default return value (the value of the right-hand-side).
A var (or let or const) is a statement that allows an optional assignment but has a return value of undefined.
You can easily test this in your console:
var foo = 42; // undefined
bar = 42 // 42
The return values alone don't answer the question, since undefined is falsey, but does show that even if JS let you put a var in a conditional it would simply always evaluate to false.
Others have mentioned for statements and that they allow declaration and instantiation of variables. This is true, but the documentation explains that for expects a statement or assigment.
Opinions may vary, but for me all this adds up to an understandable consistency not a quirk in behavior with regard to loops. A while loop is better thought of as a looping version of an if statement than akin to a for loop. If there is quirkiness in all of this, it's the for statement's wholesale divergence from the language's normal syntax.
JavaScript does not have block scope. It has function scope. So to make sure that humans and JavaScript both read the code the same way, you should manually hoist your var declarations right up to the top of functions.
Here's what JSLint says about your code:
Problem at line 1 character 8: Expected an identifier and instead saw 'var'.
Use JSLint, at least while you're learning JavaScript. You'll learn a lot very quickly. It will hurt your feelings.
JavaScript doesn't have block scope. So all var declarations are at function scope. So declaring a variable in a while expression doesn't make sense in JavaScript.
Additionally, you should end your statements with a semicolon. It's not strictly necessary, but it's highly recommended.
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.
This question already has answers here:
Explain the encapsulated anonymous function syntax
(10 answers)
Closed 7 years ago.
I'm reading up on JavaScript IIFE and so far the understand concept, but I am wondering about the outside parenthesis. Specifically, why are they required? For example,
(function() {var msg='I love JavaScript'; console.log(msg);}());
works great, but
function() {var msg='I love JavaScript'; console.log(msg);}();
generates a syntax error. Why? There are lots of discussions on IIFE, but I'm not seeing a clear explanation about why the parentheses are required.
There are two ways to create functions in JavaScript (well, 3, but let's ignore new Function()). You can either write a function declaration or write a function expression.
A function declaration in itself is a statement and statements by themselves don't return values (let's also ignore how the debugging console or Node.js REPL print return values of statements). A function expression however is a proper expression and expressions in JavaScript returns values that can be immediately used.
Now, you may have seen people saying that the following is a function expression:
var x = function () {};
It may be tempting to conclude that the syntax:
function () {};
is what makes it an expression. But that's wrong. The syntax above is what makes it an anonymous function. And anonymous functions can either be a declaration or an expression. What makes it an expression is this syntax:
var x = ...
That is, everything to the right of an = sign is an expression. Expressions make it easier to write math formulas in programming languages. So in general everywhere that math is expected to be processed is an expression.
Some of the forms of expressions in JavaScript include:
everything to the right of an = operator
things in braces () that are not function call braces
everything to the right of a math operator (+,-,*,/)
all the arguments to the ternary operator .. ? .. : ..
When you write:
function () {}
it is a declaration and does not return a value (the declared function). Therefore trying to call the non-result is an error.
But when you write:
(function () {})
it is an expression and returns a value (the declared function) which may be used immediately (for example, may be called or may be assigned).
Note the rules for what counts as expressions above. From that it follows that braces are not the only things that you can use to construct an IIFE. Below are valid ways for constructing IIFEs (because we write function expressions):
tmp=function(){}()
+function(){}()
-function(){}()
0/function(){}()
0*function(){}()
0?0:function(){}()
(function(){}())
(function(){})()
You may actually see one of the above non-standard forms (particularly the + version) in third-party libraries, because they want to save one byte. But I strongly advise you to only use the brace forms (either are fine), because they are widely recognized as IIFEs by other programmers.
The version of IIFE that is wrapped in parenthesis works, because this marks the declaration of the internal function declaration as an expression.
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
For more detailed explanation please see:
Advanced JavaScript: Why is this function wrapped in parentheses?
HINT:
The invocation operator (()) only works with expressions, not declarations.
This will be a long-winded answer, but will give you the necessary background. In JavaScript there are two ways functions can be defined:
A function definition (the classical kind)
function foo() {
//why do we always use
}
and then the more obscure type, a function expression
var bar = function() {
//foo and bar
};
In essence the same thing is going on at execution. A function object is created, memory is allocated, and an identifier is bound to the function. The difference is in the syntax. The former is itself a statement which declares a new function, the latter is an expression.
The function expression gives us the ability to insert a function any place where a normal expression would be expected. This lends its way to anonymous functions and callbacks. Take for instance
setTimeout(500, function() {
//for examples
});
Here, the anonymous function will execute whenever setTimeout says so. If we want to execute a function expression immediately, however, we need to ensure the syntax is recognizable as an expression, otherwise we have ambiguity as to whether of not we mean a function expression or statement.
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
Here sumOfSquares is immediately invoked because it can be recognized as an expression. fourteen becomes 14 and sumOfSquares is garbage-collected. In your example, the grouping operator () coerces its content into an expression, therefore the function is an expression and can be called immediately as such.
One important thing to note about the difference between my first foo and bar example though is hoisting. If you don't know what that it is, a quick Google search or two should tell you, but the quick and dirty definition is that hoisting is JavaScript's behavior to bring declarations (variables and functions) to the top of a scope. These declarations usually only hoist the identifier but not its initialized value, so the entire scope will be able to see the variable/function before it is assigned a value.
With function definitions this is not the case, here the entire declaration is hoisted and will be visible throughout the containing scope.
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"
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);
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.