Ben Aston
Ben Aston

Reputation: 55729

Javascript - why is this expression invalid?

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

Answers (4)

James Wakefield
James Wakefield

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

João Pinho
João Pinho

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

Ben Parsons
Ben Parsons

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

Artem Sobolev
Artem Sobolev

Reputation: 6069

throw is a statement, not expression. You can use only expressions in ternary if operator.

Upvotes: 4

Related Questions