Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Operator Precedence in JavaScript

Tech May 15 1

Introduction

I once had an embarrassing moment while trying to extract the current year. I wrote code like this:

new Date().getFullYear()

At that moment, I felt uncertain because I wasn't sure whether the . operator or the new keyword executes first. I quickly tested it in the console and—phew—no error occurred. The new operation runs first in this case.

Let's try something more adventurous by removing the parentheses after Date:

new Date.getFullYear()

This time, the browser threw an error. Why?

Or perhaps you've encountered baffling code snippets like this:

[[[] == []] + []][+![]][+![]] // Returns 'f'

If expressions like this leave you scratching your head, it's time to learn about operator precedence.

Understanding Expressions

According to MDN, operator precedence determines the order in which operations are evaluated in an expression. This concept exists specifically because expressions need a defined evaluation order. Before diving into precedence, let's establish what an expression actually is.

A practical (though not entirely rigorous) definition that resonates with many developers:

An expression is any piece of code that produces a value and can be placed wherever a value is expected.

You can test whether something qualifies as an expression by assigning it to a varible. If no error occurs, you've got an expression:

// Simple values
42

// Constructor calls
new Map()

// Assignment operations (chained assignments are valid)
a = b = 15

// Conditional expressions
temperature > 30 ? "hot" : "cold"

// Function expressions
const fn = function() { return 42; }

// Identifiers (variables)
counter

JavaScript categorizes expressions into several types:

  • Primitive expressions: Literals, keywords, and variables
  • Literal expressions: Array and object literals
  • Function definition expressions: Anonymous and named functions
  • Property access expressions: Dot notation and bracket notation
  • Call expressions: Function invocations with parentheses
  • Object creation expressions: Constructor calls with new

Precedence, Associativity, and Evaluation Order

MDN defines precedence as the rule that determines evaluation order for operators in an expression. But there's another concept at play: associativity.

Consider these examples:

let result = !true && false;
let sum = 1 + 2 + 3;

In the first example, !true is evaluated before the && operation. In the second, additions occur from left to right. These behaviors aren't coincidental—they're governed by precedence and associativity rules.

Precedence dictates that higher-priority operators bind more tightly to their operands, essentially as if wrapped in invisible parentheses. Associativity handles operators with equal precedence, specifying whether they group left-to-right or right-to-left.

Let's revisit the Date example that caused confusion:

// Grouping interpretation: (new Date()) followed by .getFullYear()
new Date().getFullYear()

// Grouping interpretation: new (Date.getFullYear()) which throws an error
new Date.getFullYear()

The error in the second form stems from precedence. According to MDN's operator precedence table:

  • The new operator with parentheses (like new Date()) has precedence level 19
  • The new operator without parentheses (like new Date) has precedence level 18
  • Property access with . has precedence level 19

This precedence difference explains why the two forms behave differently.

Associativity in action:

// Right-associative: equivalent to result = (!(value))
let enabled = !false;

// Left-associative: equivalent to ((1 + 2) + 3) + 4
let total = 1 + 2 + 3 + 4;

// Right-associative ternary: equivalent to x ? a : (y ? b : c)
let status = x ? "yes" : y ? "pending" : "no";

Operators and Expression Building

At its core, an operator combines expressions to form new expressions:

// Primitive expression
42

// Unary operator applied to expression
!42

// Binary operator combining two expressions
10 + !42

// Ternary operator combining three sub-expressions
isValid ? successValue : errorValue

Operators essentially "glue" nearby expressions together, building increasingly complex expressions until a final value emerges.

Further Exploration

The rules governing operator precedence and associativity form the foundation for understanding how JavaScript interprets complex expressions. Once these concepts become intuitive, code that initially appeared cryptic becomes readable.

Consider analyzing this expression to test your understanding:

(+![] + ![])[+!+[]] + ([]+{})[+!+[]]

Breaking it down using precedence rules reveals its structure and ultimate output.

To deepen your knowledge:

  • Study the complete operator precedence table on MDN
  • Practice by manually parsing complex expressions before testing them
  • Build abstract syntax trees mentally to understand evaluation order

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.