Why doesn't logical OR work with error throwing in JavaScript?

前端 未结 5 1099
慢半拍i
慢半拍i 2021-02-06 20:41

This is a pretty common and useful practice:

// default via value
var un = undefined
var v1 = un || 1

// default via a function call
var myval = () => 1
var          


        
5条回答
  •  星月不相逢
    2021-02-06 21:00

    Your problem is that an assignment expects an expression but you give it a statement

    The Syntax for initializing/assigning a variable is:

    var|let|const  = 
    

    but you use

    var|let|const  = 
    

    which is invalid Syntax.

    Expressions

    An expression is something that produces a value.

    What is a "value"?

    A value is anything that is a type in Javascript

    • Numbers
    • Strings
    • Booleans
    • Objects
    • Arrays
    • Symbols

    Examples for Expressions:

    Literals

    var x = 5;
    

    x is assigned the value "5"

    A function call

    var x = myFunc();
    

    myFunc() produces a value that is assigned to x

    The produced value of a function is its return value - A function always returns, and if it doesn't explicitly, it returns undefined.

    Functions have the added benefit of being able to contain statements in their body - Which will be the solution to your question - But more on that later.

    Statements

    A statement is something that performs an action. For Example:

    A loop

    for (var i = 0; i < 10; i++) { /* loop body */ }
    

    This loop performs the action of executing the loop body 10 times

    Throwing an error

    throw new Error()
    

    Unwinds the stack and stops the execution of the current frame

    So why can't we mix both?

    When you want to assign to a variable, you want an expression because you want the variable to have a value.

    If you think about it, it should be clear that it will never work with a statement. Giving a variable an "action" is nonsense. What is that even supposed to mean?

    Therefore you cannot use the throw statement since it does not produce a value.

    You can only have one or the other. Either you are (expression) something or you do (statement) something.

    A fix

    You can convert any statement into an expression by wrapping it in a function, I suggest using an IIFE (Immediately invoked function expression) - basically a function that invokes itself - to do just that

    var x = 5 || (() => throw new Error())()
    

    This works because the right side is now a function and a function is an expression which produces a value, The value is undefined in this case, but since we stop executing it doesnt matter anyways.

    Future Possibilities

    Technically there is nothing that prevents this from working.

    Many languages (c++, ...) actually already treat throw as an expression. Some (kotlin, ...) even leave out statements completely and treat everything as an expression.

    Others (c#, php, ...) provide workarounds like the ?? null-concealing or ?. elvis operator to solve this very use case.

    Maybe in the future we get one of those features into the ecmascript standard (there is even an open proposal to include this) until then your best bet is to use a function like:

    function assertPresent(value, message)
    {
      if(!value) {
        throw new Error(message);
      } else {
        return value;
      }
    }
    

提交回复
热议问题