Javascript Jumpstart - Operators

All about operators, operator precedence and short circuiting

·

10 min read

Javascript Jumpstart - Operators

What we'll cover

  • What are operators

  • Unary vs Binary operators

  • Arithmetic operators and Logical operators

  • Operator precedence and associativity

What are operators

  • In JavaScript, the operator is a built-in function.

  • We cannot access the contents of operators but under the hood they are functions.

  • , comma operators are used to separate different expressions.

  • = assignment operator used to assign value to a variable.

  • + plus operator used to add variables.

  • There are numerous operators and when using multiple operators on a single line precedence of operators comes into play!

Unary vs Binary operators

  • Unary operators have a single operand/argument.

      // examples of unary operators
      a++;
      +a
      delete obj.a
      typeof a
      new Object()
    
  • Binary operators have two operators/arguments.

      // examples of binary operators
      a=5 
      a+b
      a += 5
      a === b
      a && b 
      a+b+c
    
  • Infix notation

    1. Here the operator is used between operands.

    2. Examples of these operators are + = || > < (etc...)

    // examples of infix notation
    a = true
    a+b 
    a += 5 
    a || b 
    a>b
  • Prefix notation

    1. Here the operator is used before the operand.

    2. Examples of these operators ++, delete, new (etc...)

    // examples of prefix notation
    ++a
    delete obj.a
    typeof a
  • Postfix notation

    1. Here the operator is used after the operand.

    2. () parenthesis is also an operator, it is unary and has postfix notation.

    // examples of postfix notation
    a++
    myFunction()
  • Let's see a few operators in action to see how they work.

      let c = "1";
      // unary + to convert other types to number
      console.log(+c); // 1
      // convert other type to Number using Number() function
      console.log(Number(c)); // 1
    
      c = undefined;
      console.log(+c); // NaN
    
      // unary -
      c = "5";
      // JavaScript tries to convert value to number type if possible
      console.log(-c); // -5
      c = "abc";
      // here it is not possible
      console.log(-c); // NaN
    
      // increment operator ++
      let d = 5;
      // prefix notation
      ++d;
      console.log(d); // 6
      // postfix notation
      d++;
      console.log(d); // 7
      // increment operator
      console.log(++d); // 8 -> here d is incremented and returns result
      console.log(d++); // 8 -> here d returned and then incremented
      consoel.log(d) // 9
      // decrement operator
      console.log(d--); // 9
      console.log(d); // 8
      console.log(--d); // 7
      console.log(d); // 7
    

    Note: ++ or -- used in prefix increments the operand and then returns the result. But in postfix, the value is returned (before the increment or decrement) and then incremented or decremented. Be careful how you use this.

Arithmetic operators

  • Associativity indicates whether an operator is left-associative or right-associative. Left-associative operators are evaluated from left to right, while right-associative operators are evaluated from right to left.

  • Precedence determines the order in which operators are evaluated. Operators with higher precedence are evaluated first.

OperatorAssociativityPrecedence
**RightHighest
*,/,%LeftHigh
+,-LeftMedium
<,<=,>,>=NoneLow
==,!=NoneLow
===,!==NoneLow
&&LeftLowest
OR operatorLeftLowest
  • You can override the precedence using parentheses to group operations and enforce a specific evaluation order.

  • A few examples of operators we have discussed and some behaviours of these operators with different value types.

// explore arithmetic operators and associativity

// declaring variables
let a, b;
// assigning values
a = 1; b = 2;

// binary +
// a -> left hand side operand
// b-> right hand side operand
console.log(a + b); // 3

// binary `*`
console.log(a * b); // 2

// binary `/`
// javascript has only one number type, no difference b/w decimal and integer
console.log(a / b); // 0.5

// binary `-`
console.log(a - b); // -1

// reassign variables
a = "abc";
b = 5;

// JavaScript automatically converts number type to string and concatenates string
console.log(a + b); // "abc5"

// NaN when we try to do any aritmetic operation on operands that are not both number type
// NaN is number value type
console.log(a * b); // NaN
console.log(a / b); // NaN
console.log(a - b); // NaN
null * undefined; // NaN

a = "Hello";
b = "World";
// string concatenation
console.log(a +" "+ b); // "Hello World"

Arithmetic operators and logical comparison

  • Here we will look at > < >= <= == != === !==

  • === is a strict equality operator and !== is a strict inequality operator

  • Comparison operators always return true or false, it doesn't matter what values we compare!

let a, b;
a = 5;
b = 7;
c = 5;

// > <
console.log(a < b); // true
console.log(a > b); // false

// >= <=
console.log(a <= c); // true
console.log(a >= c); // true

// comparing string values
let myStr1, myStr2, myStr3;
myStr1 = "abc";
myStr2 = "bcd";
myStr3 = "Bcd";

// these are compared character by character
console.log(myStr1 > myStr2); // false
console.log(myStr1 < myStr2); // true

// lexically uppercaseLetter > lowercaseLetter
console.log(myStr1 > myStr3); // true !!


// Equality operators
let myStr = "0";
let myNumber = 0;
let myBool = false;
// avoid using equality and inequality operators
// Happens due to HIDDEN CONVERSION aka COERCION
// myStr is coerced to number and then compared to mynumber
console.log(myStr == myNumber); // true
// here fasle is coerced to number value
// false boolean value is always coerced to 0
// true boolean value is always coerced to 1
console.log(myNumber == myBool); // true
console.log(myStr == myBool); // true
// !=
// automatically performs COERCION and we get unexpected output!!
console.log(myStr != myNumber); // false

// Strict equality and inequality
// !==
// expected output!
console.log(myStr !== myNumber); // true
// ===
// here we are comparing value and type of that value
// if types are different we do not perform any coercion
// we must explicitly convert value to required type!
console.log(myStr === myNumber); // false
console.log(myStr === myNumber); // false
console.log(myStr === myNumber); // false
// null and undefined
console.log(null === undefined); // false
// null -> has null value type
// undefined -> undefined value type

// here null and undefined are COERCED to number type 0
console.log(null == undefined); //true
// associativity left-to-right for ===
// associativity comes into play when there are multiple operators on same line
console.log(0 === "" === null === undefined === false); // true
  • The recommended way of comparing variables is to use === the strict equality or !== the strict inequality operator.

  • Comparison operators are often used in if-else statements and ternary operators. *we will explore conditionals in a later part

Logical operators

  1. OR Operator ||

    • When || operator finds the first truthy value in the sequence, it returns that operand and stops.

    • When || operator finds all falsy values in sequence, it returns the last operand.

    • A note on falsy values, in javascript "", 0, null, undefined, false, NaN all evaluate to false when converted to boolean values.

    // || evaluates left-to-right
    console.log(true || false); // true
    console.log(false || true); // true

    // JS convert non-empty string to boolean -> true
    // JS convert empty string to boolean -> false
    console.log("abc" || ""); // "abc"
    console.log("" || "abc"); // "abc"
    // || reaches last operator in sequence it will return last operand without converting to boolean

    console.log("" || ""); // ""

    // all these values are falsy -> when converted to boolean all are false!!
    console.log("" || 0 || null || undefined || NaN || false); // false

    let city;
    const defaultCity = "New York";
    console.log(city || defaultCity); // "New York"
    let myCity = city || defaultCity;
    console.log(myCity); // "New York";
  1. AND Operator &&

    • When && operator finds the first falsy value in the sequence, it returns that operand and stops.

    • When && operator finds all truthy values in sequence, it returns the last operand.

    • A note on truthy values, in javascript all values apart from the falsy values discussed above are truthy!

    console.log(true && false); // false

    console.log(false && true); // false

    // chain several && operators
    // returns first falsy value and stops!
    console.log("abc" && 10 && false && "" && "abcd"); // false
    console.log('abc' && 10 && true && 123 && "string"); // "string"
  1. NOT Operator !

    • the ! operator is known as the logical NOT operator or the negation operator. It is a unary operator, meaning it operates on a single operand.

    • It converts the operand to a boolean value. If the operand is falsy (e.g., false, 0, null, undefined, NaN, or an empty string), the result is true. If the operand is truthy (e.g., a non-zero number, non-empty string, or an object), the result is false.

    • It negates the boolean value obtained in the previous step. If the boolean value is true, the result of the ! operator is false. If the boolean value is false, the result is true.

    console.log(!"abc"); // false
    console.log(!""); // true
    console.log(!0); // true
    console.log(!undefined); // true
    console.log(!null); // true
  1. NOT-NOT Operator !!

    • Quick truthy falsy check using !! operator in prefix notation.

    • This allows us to convert the value of any type to a boolean.

    • These operators are used in different cases like the assignment of value to a variable or if-else statement or while-do loop.

    console.log(!!null); // false
    console.log(!!10); // true

Short-circuiting in javascript

This is related to the truthy falsy code we saw earlier, but here's an in-depth explanation so we can understand this clearly. *This is very powerful when writing code in react (a very popular javascript ui library) or nodejs server-side code to implement business logic.

  • Short-circuiting refers to the behaviour of logical operators (&& and ||) where the evaluation of the second operand is skipped under certain conditions. This behaviour can be leveraged to write concise and efficient code.

  • There are two types of short-circuiting:

  1. Short-circuiting with the logical AND operator (&&):

    • When the left operand of && is falsy (e.g., false, 0, null, undefined, NaN, or an empty string), the result is the left operand itself, and the right operand is not evaluated. This is because if the left operand is falsy, the overall expression can never be truthy regardless of the value of the right operand.

    • When the left operand of && is truthy, the result is the value of the right operand. The right operand is evaluated only if the left operand is truthy because the truthiness of the overall expression depends on both operands being truthy.

  2. Short-circuiting with the logical OR operator (||):

    • When the left operand of || is truthy, the result is the left operand itself, and the right operand is not evaluated. This is because if the left operand is truthy, the overall expression can never be falsy regardless of the value of the right operand.

    • When the left operand of || is falsy, the result is the value of the right operand. The right operand is evaluated only if the left operand is falsy because the falsiness of the overall expression depends on both operands being falsy.

    // Short-circuiting is often used in conditional statements and 
    // can be helpful for writing concise code and avoiding unnecessary evaluations. 
    // Here are a few examples:

    // Short-circuiting with logical AND (&&)
    let name = '';
    let greeting = name && 'Hello, ' + name;
    console.log(greeting); // Output: ''

    // Short-circuiting with logical OR (||)
    let defaultValue = 'Default Value';
    let value = null;
    let result = value || defaultValue;
    console.log(result); // Output: 'Default Value'

In the first example, since name is an empty string (falsy), the evaluation of the right operand ('Hello, ' + name) is skipped, and the value of greeting remains an empty string.

In the second example, value is null (falsy), so the evaluation proceeds to the right operand, resulting in result being assigned the value of defaultValue.

This article is packed with things we should be aware of in javascript and especially when we move to conditional statements. These always come in handy! To see a detailed list of operator precedence go here. (Mozilla developer documentation for javascript)

Now we are in a good position to explore statements and expressions in javscript, so next up is Javascrip Jumpstart - Expressions vs Statements