Home Chapter 4: Expressions and Operators
Post
Cancel

Chapter 4: Expressions and Operators

Expressions and Operators

An expression is a phrase of JavaScript that can be evaluated to produce a value. A constant literal like 42 is an expression. A variable name like i is an expression. A more complex expression is i++. This expression uses the ++ increment operator to increment the value of the variable i. We will see many other examples of expressions in this chapter.

An operator is a special kind of JavaScript expression that performs a computation on one or more operands (values, literals, variables, etc.) and returns a result. Arithmetic operators like * and % are the most familiar, but JavaScript also supports a rich set of bitwise operators, comparison operators, equality operators, and more. We’ll cover all of these in this chapter.

Primary Expressions

The simplest expressions, known as primary expressions, are those that stand alone—they do not include any simpler expressions. Primary expressions in JavaScript are constant or literal values, certain language keywords, and variable references. They include the following:

  • A literal value such as 42 or "Hello"
  • A variable that is not surrounded by () or [] or used as a property of an object
  • reference to a variable, constant or property of the global object, such as PI or undefined
  • certain language keywords: this, true, false, null, Infinity, and NaN

Object and Array Initializers

An object initializer is a comma-separated list of zero or more pairs of property names and associated values, enclosed in curly braces. A property name is either a JavaScript identifier or a string literal (the empty string is allowed). A property value is any JavaScript expression; the value of the expression (it may be a literal value, a variable value, or a more complex expression) becomes the value of the property. Here are some examples:

1
2
3
4
5
6
7
8
let empty = {}; // An object with no properties
let point = { x: 0, y: 0 }; // Two numeric properties
let p2 = { x: point.x, y: point.y+1 }; // More complex values
let book = {
    "main title": "JavaScript", // Property names include spaces,
    'sub-title': "The Definitive Guide", // and hyphens, so use string literals
    "for": "all audiences", // for is a reserved word, so quote
}

An array initializer is a comma-separated list of zero or more expressions enclosed in square brackets. The array initializer evaluates to a newly created array initialized with the values of the expressions. For example:

1
2
3
4
5
6
7
8
let primes = [2, 3, 5, 7]; // An array of 4 values, delimited with [ and ]
let empty = []; // An empty array with no elements
let points = [ // An array with 2 objects
    { x: 0, y: 0 },
    { x: 1, y: 1 }
];
// a sparse array with 3 elements
let sparseArray = [1,,,,5];

A single trailing comma is allowed after the last expression in an array initializer and does not create an undefined element. A trailing comma is often useful when adding a new element, property, or method to an existing array or object, and can make version-control diffs cleaner.

Function Definition Expressions

A function definition expression defines a JavaScript function, and the value of such an expression is the newly defined function. Such expressions can be stored in variables, properties, and array elements. For example:

1
2
3
4
5
6
7
8
9
10
11
// Compute the distance between Cartesian points (x1,y1) and (x2,y2).
let distance = function(x1, y1, x2, y2) {
    let dx = x2 - x1;
    let dy = y2 - y1;
    return Math.sqrt(dx*dx + dy*dy);
};
// A recursive function expressed as a function expression
let factorial = function(n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
};

The shorhand arrow function syntax introduced in ES6 is also a kind of function definition expression. See the section Arrow Functions for more information.eg.

1
2
3
  let square = x => x*x; // One parameter, x.  Returns x squared
  let f = () => 42; // No parameters.  Returns the number 42
  let g = (x,y) => { let z = x*x + y*y; return Math.sqrt(z); }; // Two parameters

Property Access Expressions

A property access expression evaluates to the value of an object property or an array element. JavaScript defines two syntaxes for property access:

1
2
expression . identifier
expression [ expression ]

The first expression should evaluate to an object, and the second should evaluate to a string that contains the name of the property. The dot notation is shorter and generally preferred. But the square bracket notation is required if the property name contains spaces or punctuation characters or if it is a number (such as a two-dimensional array subscript). For example:

1
2
3
4
5
6
7
8
9
let book = {
    "main title": "JavaScript", // Property names include spaces,
    'sub-title': "The Definitive Guide", // and hyphens, so use string literals
    "for": "all audiences", // for is a reserved word, so quote
}
book["main title"] // => "JavaScript": access a property name that has spaces
book['sub-title'] // => "The Definitive Guide": access a property name that contains a hyphen
book["for"] // => "all audiences": access a property name that is a reserved word
book.for // => SyntaxError: invalid identifier stands alone

The square bracket notation is also used to access properties when the property name is not static but is itself stored in a variable:

1
2
3
4
let addr = "";
for(let i = 0; i < 4; i++) {
    addr += customer["address" + i] + '\n';
}

Conditional Property Access Expressions / Optional Chaining

The ?. operator functions similarly to the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.

1
2
3
expression ?. identifier
expression ?.[ expression ]
expression ?. ( arguments )

This is a short-circuiting operator, meaning that if the left operand evaluates to a nullish value (null or undefined), the right operand is not evaluated. This is opposite behavior of the . chaining operator which will evaluate the right operand even if the left operand is nullish.

1
2
3
4
5
6
7
8
9
let a = { b: null };
a?.b; // null
a?.c; // undefined

let a = { b: { c: 3 } };
a?.b; // { c: 3 }
a?.b.c; // 3
a?.c; // undefined
a.b?.c?.d; // undefined

Invocation Expressions

An invocation expression is JavaScript’s syntax for calling (or executing) a function or method. It starts with a function expression that identifies the function to be called. Then it uses parentheses to indicate the arguments to be passed to the function. For example:

1
2
3
4
5
6
// Invoke the function f:
f(0); // f is the function expression; 0 is the argument expression
// Invoke the function Math.max():
Math.max(x,y,z); // Math.max is the function; the arguments are x, y, and z
// Compute the distance between the points (x1,y1) and (x2,y2):
let dist = Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));

Conditional invocation expressions are a new feature of ES2020. They are similar to the conditional property access expressions, but instead of conditionally accessing a property, they conditionally invoke a function. The syntax is as follows:

1
2
3
4
5
6
7
expression ?. ( arguments )

// Example
let a = { b: { c: () => console.log('hello') } };
a?.b?.c(); // logs hello
a = null;
a?.b?.c(); // does nothing

Object Creation Expressions

An object creation expression creates a new object and invokes a function (called a constructor) to initialize the properties of that object. JavaScript provides a traditional class-based object-oriented model, but it also supports a prototype-based model. The object creation expression syntax is the same for both models, but the semantics differ. We’ll begin with the class-based model.

The new keyword is a unary operator that creates and initializes a new object. The new keyword must be followed by a function invocation. A function used in this way is called a constructor and serves to initialize a newly created object. JavaScript has built-in constructors for common data types, such as String() and Date(), but we can also define our own constructors. We’ll see how to do that in the next chapter. Here are some examples of object creation expressions:

1
2
3
new Object() // Create an empty object: same as {}.
new Point(2,3) // Create a new Point object.
new Date() // Create a new Date object.

If no arguments are passed to the constructor function, then the empty parentheses may be omitted. The following are all examples of object creation expressions:

1
2
3
4
5
6
new Object
new Object()
new Point(2,3)
new Point()
new Date
new Date()

Operator Overview

JavaScript defines a number of operators that can be used to manipulate values. Operators are represented by punctuation characters such as + and =. The values that an operator acts on are called operands. Operators that take a single operand, such as the ! operator, are called unary operators. Operators that take two operands, such as the familiar arithmetic operators, are called binary operators. The special ternary operator ? : is the only JavaScript operator that takes three operands: a condition followed by a ? and then two expressions separated by a :. The ternary operator is sometimes called a conditional operator since it is the only JavaScript operator that evaluates a condition and returns one value if the condition is true and a different value if the condition is false.

JavaScript defines a number of operators, but they can be grouped into the following categories:

  • Arithmetic operators .eg. + (addition), - (subtraction), * (multiplication), / (division), % (modulo), ++ (increment), – (decrement)
  • Bitwise operators .eg. & (bitwise AND),(bitwise OR), ^ (bitwise XOR), ~ (bitwise NOT), « (left shift), » (right shift), »> (unsigned right shift)
  • Comparison operators .eg. == (equality), === (identity), != (inequality), !== (nonidentity), > (greater than), >= (greater than or equal to), < (less than), <= (less than or equal to)
  • Equality operators .eg. == (equality), === (identity), != (inequality), !== (nonidentity)
  • Relational operators .eg. > (greater than), >= (greater than or equal to), < (less than), <= (less than or equal to)
  • Logical operators .eg. && (logical AND), (logical OR), ! (logical NOT)
  • String operators .eg. + (concatenation)
  • Conditional (ternary) operator .eg. ? : (conditional)
  • Comma operator .eg. , (comma)
  • Unary operators .eg. delete, typeof, void, + (unary plus), - (unary minus), ~ (bitwise NOT), ! (logical NOT), ++ (increment), – (decrement)
  • Assignment operators .eg. = (assignment), += (compound assignment), -= (compound assignment), *= (compound assignment), /= (compound assignment), %= (compound assignment), «= (compound assignment), »= (compound assignment), »>= (compound assignment), &= (compound assignment), ^= (compound assignment),= (compound assignment)
  • Destructuring assignment operators .eg. = (assignment), [ ]= (array element), { }= (object property)
  • Spread operator .eg. … (spread)
  • Property accessors .eg. . (dot), [ ] (square bracket)
  • Grouping operator .eg. ( )
  • Exponentiation operator .eg. ** (exponentiation)
  • Void operator .eg. void
  • Await operator .eg. await
  • Super operator .eg. super
  • In operator .eg. in

Number of Operands

JavaScript operators are classified by the number of operands they expect. Most operators are binary operators that expect two operands, but there are a handful of unary operators and one ternary operator. The ternary operator is the conditional operator, and it is the only JavaScript operator that takes three operands. The unary operators are:

  • The typeof operator expects one operand, evaluates it, and returns a string indicating the operand’s type.
  • The delete operator expects one operand whose value should be a property reference. It evaluates that operand and then removes the property from the object referenced by the operand. It does not remove variables or functions declared with the var, let, or const keywords.
  • The void operator expects a single operand and evaluates it and then returns undefined.
  • unary plus (+) and minus (-) operators expect a single operand. They attempt to convert it to a number, if it is not already, and then change the sign of the result.
  • The increment (++) and decrement (–) operators expect a single operand. They attempt to convert it to a number, if it is not already, and then add or subtract 1 from the result.
  • The ternary conditional operator (?:) expects three operands. It is the only operator in JavaScript that expects three operands. It is a conditional operator that is sometimes called the conditional operator.

Operator Precedence

Operator precedence determines how operators are parsed concerning each other. Operators with higher precedence become the operands of operators with lower precedence. For example, multiplication has higher precedence than addition, so 2 + 3 * 4 evaluates to 14 rather than 20. Operators of the same precedence are parsed from left to right. So 6 - 3 + 2 evaluates to 5 rather than 1 because the subtraction happens first. The following table lists all JavaScript operators from highest precedence to lowest. Operators on the same line have the same precedence. The table also includes the associativity of each operator, which is either left-to-right or right-to-left.

OperatorDescriptionAssociativity
. [] ()Memberleft-to-right
newCreationright-to-left
++ –Postfix increment/decrementleft-to-right
++ – + - ! ~ typeof void deleteUnary prefix operatorsright-to-left
**Exponentiation (ES2016)right-to-left
* / %Multiplication, division, moduloleft-to-right
+ -Addition/concatenation, subtractionleft-to-right
« » »>Bitwise shiftleft-to-right
< <= > >= in instanceofRelationalleft-to-right
== != === !==Equalityleft-to-right
&Bitwise ANDleft-to-right
^Bitwise XORleft-to-right
|Bitwise ORleft-to-right
&&Logical ANDleft-to-right
||Logical ORleft-to-right
?:Conditionalright-to-left
= += -= *= /= %= «= »= »>= &= ^= |=Assignmentright-to-left
yieldYield (ES2015)right-to-left
,Commaleft-to-right

Arithmetic Operators

The JavaScript arithmetic operators are addition (+), subtraction (-), multiplication (*), division (/), and remainder (%). These operators work as they do in most other programming languages when they are used with numbers. For example, 2 + 3 is 5, and “hello” + “ “ + “there” is the string “hello there”. But JavaScript also supports arithmetic on non-numeric values. If either operand to an arithmetic operator is a string, the other operand is converted to a string, and the result is string concatenation. For example, 5 + “ objects” is the string “5 objects”, and “my” + “string” is the string “mystring”. If the string operand is on the left side— that is, if the code is written as a string literal or variable followed by an operator and a number—then the operation is not commutative. For example, “5” + 5 is “55”, not 10. The + operator is the only JavaScript operator that supports string concatenation. If any operand to the + operator is an object, the object is converted to a primitive value as follows and then the operation is carried out on the primitive value:

  • If an object has a valueOf() method that returns a primitive value, JavaScript calls that method, and if the return value is a primitive value, it uses that value for the arithmetic operation.
  • Otherwise, if an object has a toString() method that returns a primitive value, JavaScript calls that method, and if the return value is a primitive value, it uses that value for the arithmetic operation.
  • Otherwise, JavaScript cannot convert the object to a primitive value, so it throws a TypeError.

The - (subtraction) operator is not defined for objects, but the other arithmetic operators work the same way as +. They convert objects to primitives and then perform the operation on the primitive value. The - operator is defined for primitive values, however, and it performs subtraction. If either operand of - is not a number, it is converted to one. If that conversion fails, the operation returns NaN. The other arithmetic operators work only with numbers, and if either operand is not a number, it is converted to one. If that conversion fails, the operation returns NaN. The % (remainder) operator is defined only for numbers, and it returns the remainder of dividing its first operand by its second. The remainder has the same sign as the dividend (the first operand) and a smaller absolute value than the divisor (the second operand). For example, 5 % 2 is 1, but -5 % 2 is -1, and 1 % -2 is 1. The / operator performs division, and the result of the operation is the quotient. If either operand is not a number, it is converted to one. If that conversion fails, the operation returns NaN. Division by zero is not an error in JavaScript: it simply returns Infinity or -Infinity. The / operator is the only JavaScript operator that exhibits this behavior. The other arithmetic operators return NaN when they are given a non-numeric operand. The / operator does not convert string operands to numbers, so “5” / 2 is 2.5, but “5” / 0 is Infinity, not an error. The + operator, on the other hand, does convert string operands to numbers, so “5” + 2 is “52”, not 7. The + operator also converts true to 1 and false to 0. The other arithmetic operators do not convert boolean values to numbers, so true + true is NaN, not 2.

Relational Expressions

  • Equality expressions (==, !=, ===, !==)
  • Comparison expressions (<, <=, >, >=)
  • The in operator and the instanceof operator

The in operator expects a left-side operand that is a string, symbol, or value that can be converted to a string and a right-side operand that is an object. It returns true if the left-side value is the name of a property of the right-side object. For example:

1
2
3
4
5
6
7
8
9
let point = { x: 1, y: 1 }; // Define an object
"x" in point // => true: object has property named "x"
"z" in point // => false: object has no "z" property.
"toString" in point // => true: object inherits toString method

let data = [7, 8, 9]; // An array with elements (indices) 0, 1, and 2
"0" in data // => true: array has an element "0"
1 in data // => true: numbers are converted to strings
3 in data // => false: no element 3

The instanceof operator expects a left-side operand that is an object and a right-side operand that identifies a class of objects. It returns true if the left-side object is an instance of the right-side class and false otherwise. For example:

1
2
3
4
let d = new Date(); // Create a new object with the Date() constructor
d instanceof Date // => true: d was created with Date()
d instanceof Object // => true: all objects are instances of Object
d instanceof Number // => false: d is not a Number object

Logical Expressions

  • Logical AND (&&) if the first operand is falsy, the result is that operand; otherwise, the result is the second operand.
    1
    2
    3
    4
    5
    
    let a = 1, b = 2, c = 3;
    (a || b) // => 1 is truthy, so it is the result
    (a && b) // => 2 is truthy, so it is the result
    (a || c) // => 1 is truthy, so it is the result
    (a && c) // => 3 is truthy, so it is the result
    
  • Logical OR (||) if the first operand is truthy, the result is that operand; otherwise, the result is the second operand. This operator is often used to select a value from a pair of alternatives. For example:
    1
    
    let max = max_width || preferences.max_width || 500;
    
  • Logical NOT (!) The ! operator converts its operand to a boolean value and then negates that value. It is the only JavaScript operator that takes exactly one operand, and it always returns a boolean value. If the operand is falsy, the ! operator converts it to true. If the operand is truthy, the ! operator converts it to false. eg.
    1
    2
    
    let n = 0; // Zero is falsy
    let b = !!n; // => false: apply ! twice
    

eval()

The eval() function evaluates a string of JavaScript code in the context of the specified object. The eval() function evaluates JavaScript code represented as a string. The string can contain any valid JavaScript expression, statement, or sequence of statements. For example:

1
eval("3+2") // => 5

First-defined operator (??) / Nullish coalescing operator

The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.

1
2
3
4
5
6
7
8
let height = 0;
console.log(height || 100); // 100 (because 0 is falsy)
console.log(height ?? 100); // 0 (because 0 is not null or undefined)

let height = null;
console.log(height || 100); // 100 (because null is falsy)
console.log(height ?? 100); // 100 (because null is not null or undefined)

Assignment Operators

  • Assignment (=)
  • Compound assignment (+=, -=, *=, /=, %=, **=, «=, »=, »>=, &=, ^=,=)
  • Destructuring assignment (var {a, b} = {a: 1, b: 2})

Bitwise Operators

  • Bitwise AND (&) The & operator performs a Boolean AND operation on each bit of its integer arguments. A bit is set in the result only if the corresponding bit is set in both operands. For example, 0x1234 & 0x00FF evaluates to 0x0034.
  • Bitwise OR () 
    Theoperator performs a Boolean OR operation on each bit of its integer arguments. A bit is set in the result if the corresponding bit is set in one or both of the operands. For example, 0x12340x00FF evaluates to 0x12FF.
  • Bitwise XOR (^) The ^ operator performs a Boolean exclusive OR operation on each bit of its integer arguments. Exclusive OR means that either operand one is true or operand two is true, but not both. A bit is set in this operation’s result if a corresponding bit is set in one (but not both) of the operands. For example, 0xFF00 ^ 0xF0F0 evaluates to 0x0FF0.

typeof

The typeof operator returns a string indicating the type of the unevaluated operand. operand is the string, variable, keyword, or object for which the type is to be returned. The parentheses are optional.

1
2
3
4
5
6
7
8
9
typeof "Hello World" // => "string"
typeof 10 // => "number"
typeof 5.1 // => "number"
typeof true // => "boolean"
typeof undefined // => "undefined"
typeof null // => "object"  (bug in ECMAScript, should be null)
typeof {x:1, y:2} // => "object"
typeof [1,2,3,4] // => "object"
typeof function(){} // => "function"

delete

The JavaScript delete operator removes a property from an object; if no more references to the same property are held, it is eventually released automatically.

1
2
3
4
5
6
7
8
const object1 = {};

object1.property1 = 42;

delete object1.property1;

console.log(object1.property1);
// expected output: undefined

deleting array elements leaves undefined holes in the array. If you delete a property with the delete operator, the array length is not affected. For example:

1
2
3
let a = [1,2,3];
delete a[2]; // a now has no element at index 2
2 in a // => false: no array index 2 is defined

void

The void operator evaluates the given expression and then returns undefined.

1
2
3
4
let counter = 0;
const increment = () => void counter++;
increment(); // returns undefined
counter; // returns 1

comma

The comma operator (,) evaluates each of its operands (from left to right) and returns the value of the last operand. This lets you create a compound expression in which multiple expressions are evaluated, with the compound expression’s final value being the value of the rightmost of its member expressions. This is commonly used to provide multiple parameters to a for loop. For example, if a is an array of strings, the following for loop logs each element to the console:

1
2
for (let i = 0, j = a.length; i < j; i++, j--)
  console.log('a[' + i + '] = ' + a[i]);

Made with ❤️ by Francis K.

This post is licensed under CC BY 4.0 by the author.