I've got a javascript function that needs to be executed based on a boolean value. I really like to use the && operator for this (which only executes the second part if the first results in true).
someBoolean && executeFunction();
However, when JSHint checks my code, I get the following message:
Expected an assignment or function call and instead saw an expression.
I'm wondering why JSHint throws this message. I know I can easily avoid it by using a simple if statement, but I really like the simplicity of this one. Maybe I need to fiddle a bit with some JSHint configuration? Is there some hidden danger in this line of code?
Related
I was testing some stuff on Console on Chrome and then I ran that piece of code:
alert() | window.confirm();
alert() || window.confirm();
My problem was to run both alert and confirm methods in a single line without using semicolon. It turns out that both | and || worked and I can't imagine why it worked, firstly because || means an OR operator which should run one of them not both and secondly | I don't know what it is. Can someone explain what happened and what else should work instead of ;?
A semicolon indicates the end of a statement.
If you aren't already aware, an expression is something which evaluates to a value. For example, 5, 'foobar', and myFn() are all expressions, because they evaluate to values.
Statements can be composed of multiple expressions. For example, const result = fn('foo') passes the 'foo' expression into the function call, and the function call returns a value which is assigned to result.
In your code, both lines are composed of two expressions, but each line happens to be a single statement. With this line:
alert() || window.confirm()
will first evaluate alert. Since alert returns undefined, the || operator then evaluates the expression on the right, which is window.confirm().
You can put multiple expressions together on the same by using operators like |, ||, or =. You can also evaluate multiple expressions by putting each as a separate statement, like
alert();
window.confirm();
Both will result in an alert box and a confirm dialog coming up.
alert() returns undefined, which is false-y. Therefore, window.confirm() will still run, for your example of ||.
As for a single pipe character |, that's a bitwise-OR, which you can read about here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise
The || is an operator, like + or /; it calculates something. In the case of ||, it calculates whether one OR the other value is true.
Normally, you'd use that in something like an if statement: if (i===0 || j===0) {...} but it's not restricted to that; for instance, you could put the result in a variable, then use it in an if statement later: have_zero = i===0 || j===0; ...; if (have_zero) {...}
The || (and &&) operators do have one special thing: if the left side determines the answer, they don't bother calculating the right side (called "short-circuit evaluation").
Here, you're calculating alert() || window.confirm(), so it calls alert(); as others have noted, this returns undefined which doesn't determine the answer to the ||, so Javascript then calls window.confirm(). The answer is then thrown away, because you're not putting it in a variable or otherwise using it, but that's OK - you wanted to call the methods, you weren't interested in the answer.
The following code returns an error that says
"console.log(...) is not a function"
if (4<5) console.log('hi')
(4<5) ? console.log('hi') : console.log('bye')
The following code does not return any error
if (4<5) console.log('hi')
if (4<5) console.log('hi')
Why is this so?
Without a semicolon at the end of the first line, the code tries to use return value of the first console.log as a function and call it with the argument 4<5; this is clearer if you remove the line break:
if (4<5) console.log('hi')(4<5) ? console.log('hi') : console.log('bye')
// ^^^^^^^^^^^^^^^^^^^^^^---- looks like calling `console.log` and then
// using the result as a function
There's the potential for this any time you combine leaving off semicolons (which means you're relying on an error-correction mechanism1) with expression statements. Since expression statements are, by their nature, expressions, if the parser can use them in the previous expression or statement, it will.
FWIW, astexplorer.net is a cool tool I've recently found (thanks to the Babel project). It's an interactive syntax tree explorer which can use any of several parsers to parse your code and tell you exactly how it was parsed. And from the github account, it was started by our own Felix Kling.
1 Quoting Brendan Eich:
ASI is (formally speaking) a syntactic error correction procedure. If you start to code as if it were a universal significant-newline rule, you will get into trouble.
I saw in Ractive docs this line of code:
Ractive.DEBUG = /unminified/.test(function() {/*unminified*/});
Can you explain the logic behind this ?
The function should have the same value, despite whether it has inline comments or not.
Minification will remove the comment from the code so the function becomes function() {} when regex test calls .toString() on the function, thus yielding false.
Without minification, the regex test will find the occurrence of unminified and therefore DEBUG will be true
It's almost midnight and I just got a question in my head is "for loop" a statement or a function.
I always thought it is a statement, but I did a google search on it being a function and there are indeed results for that. So what is it? And in that case what is the difference between function and statement?
A for loop is a not usually a function, it is a special kind of statement called a flow control structure.
A statement is a command. It does something. In most languages, statements do not return values. Example:
print "Hello World"
A function is a subroutine that can be called elsewhere in the program. Functions often (but not necessarily) return values. Example:
function(a) { return a * 2 }
A control structure, also known as a compound statement, is a statement that is used to direct the flow of execution. Examples:
if (condition) then { branch_1 } else { branch_2 }
for (i = 0; i < 10; i += 1) { ... }
Also worth noting is that an expression is a piece of code that evaluates to a value. Example:
2 + 2
All examples are in pseudocode, not tied to any particular language. Also note that these are not exclusive categories, they can overlap.
Out of the three language tags you've chosen, I'm only very familliar with Python, but I believe many other languages have a similar view of these concepts. All the example code here is Python.
A statement is a thing that is executed; an "instruction to do something" that the language implementation understands. e.g.
print "Hello World"
pass
def foo(n):
return n + 1
if condition:
print 'yay'
else:
print 'doh'
The above block contains a print statement, a pass statement, a function definition statement, and an if/else statement. Note that the function definition and the if/else statement are compound statements; they contain other statements (possibly many of them, and possibly other compound statements).
An expression is something that can be evaluated to produce a value. e.g.
1
"foo"
2 * 6
function(argument)
None
The above contains a numeric literal expression, a string literal expression, an expression involving numeric operators, a function call expression, and the literal None expression. Other than literals and variables, expressions are made up of other expressions. In function(argument), function and argument are also both expressions.
The key difference is that statements are instructions that tell the language implementation to "go do something". Expressions are evaluated to a value (which possibly requires to language implementation to "go do something" on the way).
A consequence of this is that anywhere you see a value (including an expression), you could substitute any other expression and you would still get something that makes some sort of sense. It may fail to compile, or throw exceptions at runtime, or whatever, but on at least some level you can understand what's going on.
A statement can never appear inside an expression (I believe this is not true in Ruby and Javascript in some sense, as they allow literal code blocks and functions which are then used as a value as a whole, and functions and code blocks contain statements; but that's kind of different from what I'm talking about). An expression must have a value (even if it's an uninteresting one like None). A statement is a command; it doesn't make sense for it to appear as part of an expression, because it has no value.
Many languages also allow expressions to be used as statements. The usual meaning of this is "evaluate this expression to get a value, then throw it away". In Python, functions that always return None are usually used this way:
write_to_disk(result)
It's used as a "command", so it looks like a statement, but technically it's an expression, we just don't use the value it evaluates to for anything. You can argue that a "bare expression" is one of the possible statements in a language (and they're often parsed that way).
Some languages though distinguish between functions that must be used like statements with no return value (often called procedures) and functions that are used like an expression, and give you errors or warnings for using a function like a statement, and definitely give you an error for using a procedure as an expression.
So, if foo is an expression, I can write 1 + foo and while it may be result in a type error, it at least makes that much sense. If foo is a statement, then 1 + foo is usually a parse error; the language implementation won't even be able to understand what you're trying to say.
A function on the other hand, is a thing you can call. It's not really either an expression or a statement in itself. In Python, you use a def statement to create a function, and a function call is an expression. The name bound to the function after you create it is also an expression. But the function itself is a value, which isn't exactly an expression when you get technical, but certainly isn't a statement.
So, for loops. This is a for loop in Python:
for thing in collection:
do_stuff(thing)
Looks like a statement (a compound statement, like an if statement). And to prove it, this is utterly meaningless (and a parse error):
1 + for thing in collection:
do_stuff(thing)
In some languages though, the equivalent of a for loop is an expression, and has a value, to which you can attempt to add 1. In some it's even a function, not special syntax baked into the language.
This answer is relevant to Python 2.7.2. Taken from the python tutorial:
"4. More Control Flow Tools
4.2. for Statements:
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence."
I've had numerous bugs happening just because of a missing return in a function. You see, when most of the code you write is in Ruby, it's easy to forget about explicit returns.
So I'd like to use something similar to JSlint (which I already use) to check that all functions return something. Yes, I think it's better to explicitly return something when it's not required than to hunt down missing returns.
So, are there any tools that would check for returns? Or maybe I can assert it in runtime in a simple manner?
Please don't suggest Coffeescript, I'm aware of its existence.
JSUnit example:
<script language="javascript" src="jsUnitCore.js"></script>
<script language="javascript">
function testWithValidArgs() {
assertEquals("someFunction should return something", "Expected REturn Value", someFunction(2, 3));
}
</script>
Just add return consistently. But to be honest, JSlint is a VERY strict checking tool. You will never get errors if you're not returning values unless you're trying to define a variable using the response of a function, but in that case it's more than logic that you add a return statement.
However, if you're still dedicated to have a return statement in every function, you should add them from the start. There is no tool that adds them.
I'm not aware of any tools that will do this out of the box. But it would not be hard to write one.
Start by using UglifyJS to parse your code into a syntax tree. Write a recursive function that examines all code, looking for function definitions. For every function you find, look at the last statement. If that one is not a return-statement, then print a warning.
(Too long for comment.)
My problem with returning something when a function has no (meaningful) return value is that it's misleading, unless it returns undefined, which defeats the purpose.
If I see a return, I have to reason about the code both in the method and at the call site.
In the function I have to determine if it ever returns anything else, why it returns the value it does, etc. The only real way around this is to return a constant that makes it obvious the it's not really returning anything, it's just to satisfy a desire to return something.
At the call site, if a return value is ignored, I need to understand why, and if it's okay to do so. If I know every function returns something, I then have to check the function to see if it's returning that special value, or go through the above process.
I'd almost rather namespace my functions into "function" and "method" namespaces at that point as a differentiater. This would allow automated testing of each namespace to make sure that all functions return something useful, all methods specifically don't, and would provide a source-level clue as to which the caller should expect.