Reputation: 55729
Why is the following expression not valid in JavaScript?
(function(){ return foo ? foo : throw "foo not set"; }())
Is it because there are constraints on the positioning of the throw keyword?
Upvotes: 1
Views: 759
Reputation: 526
My trick for a similar question
As mentioned in most other answers throw
is a statement not an expression. This simply means it can not be used in places where a value is expected to be assigned. We could create a function that will throw an error, but here I have a mechanism that won't create an additional stack-call making it hopefully easier to debug. null.throwFooNotSet()
is guaranteed to always throw an error as there will never be any properties added to the null
primitive value. I have added all the try, catch and finally statements to clear this up. The special typeof unary prefix operator (please note it is a prefix operator like +x
--x
++x
!x
and void
it is not a function so don't call it with parens (even though that actually will work) is safe to call even when a value is not defined. So perhaps everyone missed the point of this question. If you are not asking about why you can't throw from a ternary the following may be all you need.
0|| function(){
return typeof foo !== 'undefined'
? foo
: 'enter default value here'
}()
typeof doesn't work with values defined with let. but it doesn't make much sense to define globals with let anyway, in strict mode new variables can not be defined with eval, so you can find all the declared variables by analysing the static code. You can still add properties directly to the global Object, so in a browser window.MY_UGLY_GLOBAL='foo'
and this can be checked for existence by using the in
keyword, using in though won't work if the variable is declared in a closure between the global Object and the function checking it's existence... but as I said earlier, you can read the code and see if it exists or not. So really the only place it makes sense to check is the global Object, and by using in, the JS engine does not crawl the scope chain so it will be a much faster look-up. If you are minifying your script you must now be certain that you don't mangle the name of this property as it now must be referred to by it's name.
window.MY_UGLY_VAR = undefined
if ('MY_UGLY_VAR' in window)
console.log(
'despite being assigned the value undefined, "MY_UGLY_GLOBAL"'
+'is "in" the window object')
To throw from a ternary: Just call a non existent property on null.
0 || function(){
'use strict'
var valToReturn
, defaultVal = 'foobar'
//, foo = 'foo'
try {
0|| function () {
valToReturn = typeof foo !== 'undefined' ? foo : null.throwFooNotSet() }()
// let foo = 'bar'
} catch(e){
valToReturn = defaultVal
if(e.message && e.message.indexOf('throwFooNotSet') !== -1)
console.log('no value for foo')
else
console.log('es2015 let temporal dead zone')
} finally {
return valToReturn
}
}()
Upvotes: 0
Reputation: 3775
The problem is related with the type and the kind of operations you are doing:
(function(){ return foo ? foo : throw "foo not set"; }())
The ternary operator expectes an expression, and throw "" like this is a statement. If you want to use that ternary expression anyway do this instead:
function doSomething(){
return foo ? (function(){ return foo; }) : (function(){ throw "error"; });
}
try
{
var result = doSomething()();
alert(result);
}
catch(e){
alert(e);
}
Here is a fiddle with this so you can understand better: http://jsfiddle.net/9K3hv/
This way you decide the kind of operation and then you invoke it, because (function(){}) is an object of type function you can use it in a ternary expression.
Regards.
Upvotes: 1
Reputation: 1443
This question has been answered here:
JavaScript error handling: can I throw an error inside a ternary operator?
throw
is a statement and it can't be part of an expression.
Upvotes: 6
Reputation: 6069
throw
is a statement, not expression. You can use only expressions in ternary if
operator.
Upvotes: 4