Chapter 9. Operators

## Chapter 9. Operators

This chapter gives an overview of operators.

## Operators and Objects

All operators coerce (as discussed in Type Coercion) their operands to appropriate types. Most operators only work with primitive values (e.g., arithmetic operators and comparison operators). That means that objects are converted to primitives before anything is done with them. One example where that is unfortunate is the plus operator, which many languages use for array concatenation. That’s not so with JavaScript, however, where this operator converts arrays to strings and appends them:

```> [1, 2] + 
'1,23'
> String([1, 2])
'1,2'
> String()
'3'```

### Note

There is no way to overload or customize operators in JavaScript, not even equality.

## Assignment Operators

There are several ways to use the plain assignment operator:

`x = value`
Assigns to a variable `x` that has previously been declared
`var x = value`
Combines a variable declaration with an assignment
`obj.propKey = value`
Sets a property
`obj['propKey'] = value`
Sets a property
`arr[index] = value`
Sets an array element

An assignment is an expression that evaluates to the assigned value. That allows you to chain assignments. For example, the following statement assigns `0` to both `y` and `x`:

``x` `=` `y` `=` `0``;``

### Compound Assignment Operators

A compound assignment operator is written as `op=`, where `op` is one of several binary operators and `=` is the assignment operator. The following two expressions are equivalent:

````myvar` `op``=` `value`
`myvar` `=` `myvar` `op` `value````

In other words, a compound assignment operator `op=` applies `op` to both operands and assigns the result to the first operand. Let’s look at an example of using the plus operator (`+`) via compound assignment:

```> var x = 2;
> x += 3
5
> x
5```

The following are all compound assignment operators:

## Equality Operators: === Versus ==

JavaScript has two ways of determining whether two values are equal:

• Strict equality (`===`) and strict inequality (`!==`) consider only values that have the same type to be equal.
• Normal (or “lenient”) equality (`==`) and inequality (`!=`) try to convert values of different types before comparing them as with strict (in)equality.

Lenient equality is problematic in two regards. First, how it performs conversion is confusing. Second, due to the operators being so forgiving, type errors can remain hidden longer.

Always use strict equality and avoid lenient equality. You only need to learn about the latter if you want to know why it should be avoided.

Equality is not customizable. Operators can’t be overloaded in JavaScript, and you can’t customize how equality works. There are some operations where you often need to influence comparison—for example, `Array.prototype.sort()` (see Sorting and Reversing Elements (Destructive)). That method optionally accepts a callback that performs all comparisons between array elements.

### Strict Equality (===, !==)

• `undefined === undefined`
• `null === null`
• Two numbers:

````x` `===` `x`  `// unless x is NaN`
`+``0` `===` `-``0`
`NaN` `!==` `NaN`  `// read explanation that follows````
• Two booleans, two strings: obvious results
• ```> var b = {}, c = {};
> b === c
false
> b === b
true```
• Everything else: not strictly equal.

#### Pitfall: NaN

The special number value `NaN` (see NaN) is not equal to itself:

```> NaN === NaN
false```

Thus, you need to use other means to check for it, which are described in Pitfall: checking whether a value is NaN.

#### Strict inequality (!==)

A strict inequality comparison:

``x` `!==` `y``

is equivalent to the negation of a strict equality comparison:

``!``(``x` `===` `y``)``

### Normal (Lenient) Equality (==, !=)

Otherwise, if the operands are:

1. `undefined` and `null`, then they are considered leniently equal:

```> undefined == null
true```
2. A string and a number, then convert the string to a number and compare both operands via strict equality.
3. A boolean and a nonboolean, then convert the boolean to a number and compare leniently (again).
4. An object and a number or a string, then try to convert the object to a primitive (via the algorithm described in Algorithm: ToPrimitive()—Converting a Value to a Primitive) and compare leniently (again).

Otherwise—if none of the aforementioned cases apply—the result of the lenient comparison is `false`.

#### Lenient inequality (!=)

An inequality comparison:

``x` `!=` `y``

is equivalent to the negation of an equality comparison:

``!``(``x` `==` `y``)``

#### Pitfall: lenient equality is different from conversion to boolean

Step 3 means that equality and conversion to boolean (see Converting to Boolean) work differently. If converted to boolean, numbers greater than 1 become `true` (e.g., in `if` statements). But those numbers are not leniently equal to `true`. The comments explain how the results were computed:

```> 2 == true  // 2 === 1
false
> 2 == false  // 2 === 0
false

> 1 == true  // 1 === 1
true
> 0 == false  // 0 === 0
true```

Similarly, while the empty string is equal to `false`, not all nonempty strings are equal to `true`:

```> '' == false   // 0 === 0
true
> '1' == true  // 1 === 1
true
> '2' == true  // 2 === 1
false
> 'abc' == true  // NaN === 1
false```

#### Pitfall: lenient equality and strings

Some of the leniency can be useful, depending on what you want:

```> 'abc' == new String('abc')  // 'abc' == 'abc'
true
> '123' == 123  // 123 === 123
true```

Other cases are problematic, due to how JavaScript converts strings to numbers (see Converting to Number):

```> '\n\t123\r ' == 123  // usually not OK
true
> '' == 0  // 0 === 0
true```

#### Pitfall: lenient equality and objects

```> {} == '[object Object]'
true
> ['123'] == 123
true
> [] == 0
true```

However, two objects are only equal if they are they same object. That means that you can’t really compare two wrapper objects:

```> new Boolean(true) === new Boolean(true)
false
> new Number(123) === new Number(123)
false
> new String('abc') == new String('abc')
false```

### There Are No Valid Use Cases for ==

You sometimes read about valid use cases for lenient equality (`==`). This section lists them and points out better alternatives.

#### Use case: checking for undefined or null

The following comparison ensures that `x` is neither `undefined` nor `null`:

``if` `(``x` `!=` `null``)` `...``

While this is a compact way of writing this check, it confuses beginners, and experts can’t be sure whether it is a typo or not. Thus, if you want to check whether `x` has a value, use the standard check for truthiness (covered in Truthy and Falsy Values):

``if` `(``x``)` `...``

If you want to be more precise, you should perform an explicit check for both values:

``if` `(``x` `!==` `undefined` `&&` `x` `!==` `null``)` `...``

#### Use case: working with numbers in strings

``if` `(``x` `==` `123``)` `...``

The preceding checks whether `x` is either `123` or `'123'`. Again, this is very compact, and again, it is better to be explicit:

``if` `(``Number``(``x``)` `===` `123``)` `...``

#### Use case: comparing wrapper instances with primitives

Lenient equals lets you compare primitives with wrapped primitives:

```> 'abc' == new String('abc')
true```

There are three reasons against this approach. First, lenient equality does not work between wrapped primitives:

```> new String('abc') == new String('abc')
false```

Second, you should avoid wrappers anyway. Third, if you do use them, it is better to be explicit:

``if` `(``wrapped``.``valueOf``()` `===` `'abc'``)` `...``

## Ordering Operators

JavaScript knows the following ordering operators:

• Less than (`<`)
• Less than or equal (`<=`)
• Greater than (`>`)
• Greater than or equal (`>=`)

These operators work for numbers and for strings:

```> 7 >= 5
true
> 'apple' < 'orange'
true```

For strings, they are not very useful, because they are case-sensitive and don’t handle features such as accents well (for details, see Comparing Strings).

### The Algorithm

You evaluate a comparison:

``x` `<` `y``

by taking the following steps:

1. Ensure that both operands are primitives. Objects `obj` are converted to primitives via the internal operation `ToPrimitive(obj, Number)` (refer to Algorithm: ToPrimitive()—Converting a Value to a Primitive), which calls `obj.valueOf()` and, possibly, `obj.toString()` to do so.
2. If both operands are strings, then compare them by lexicographically comparing the 16-bit code units (see Chapter 24) that represent the JavaScript characters of the string.
3. Otherwise, convert both operands to numbers and compare them numerically.

The other ordering operators are handled similarly.

## The Plus Operator (+)

```> 'foo' + 3
'foo3'
> 3 + 'foo'
'3foo'

> 'Colors: ' + [ 'red', 'green', 'blue' ]
'Colors: red,green,blue'```

Otherwise, both operands are converted to numbers (see Converting to Number) and added:

```> 3 + 1
4
> 3 + true
4```

That means that the order in which you evaluate matters:

```> 'foo' + (1 + 2)
'foo3'
> ('foo' + 1) + 2
'foo12'```

### The Algorithm

``value1` `+` `value2``

by taking the following steps:

1. Ensure that both operands are primitives. Objects `obj` are converted to primitives via the internal operation `ToPrimitive(obj)` (refer to Algorithm: ToPrimitive()—Converting a Value to a Primitive), which calls `obj.valueOf()` and, possibly, `obj.toString()` to do so. For dates, `obj.toString()` is called first.
2. If either operand is a string, then convert both to strings and return the concatenation of the results.
3. Otherwise, convert both operands to numbers and return the sum of the results.

## Operators for Booleans and Numbers

Boolean operators:

Number operators:

• Arithmetic operators (see Arithmetic Operators):

````x` `+` `y``,` `x` `-` `y``,` `x` `*` `y``,` `x` `/` `y``,` `x` `%` `y`
`++``x``,` `--``x``,` `x``++``,` `x``--`
`-``x``,` `+``x````
• Bitwise operators (see Bitwise Operators):

````~``x`
`x` `&` `y``,` `x` `|` `y``,` `x` `^` `y`
`x` `<<` `y``,` `x` `>>` `y``,` `x` `>>>` `y````

## Special Operators

Here we will review special operators, namely the conditional, comma, and `void` operators.

### The Conditional Operator ( ? : )

The conditional operator is an expression:

``«``condition``»` `?` `«``if_true``»` `:` `«``if_false``»``

If the condition is `true`, the result is `if_true`; otherwise, the result is `if_false`. For example:

``var` `x` `=` `(``obj` `?` `obj``.``prop` `:` `null``);``

The parentheses around the operator are not needed, but they make it easier to read.

### The Comma Operator

``«``left``»` `,` `«``right``»``

The comma operator evaluates both operands and returns the result of `right`. Roughly, it does for expressions what the semicolon does for statements.

This example demonstrates that the second operand becomes the result of the operator:

```> 123, 'abc'
'abc'```

This example demonstrates that both operands are evaluated:

```> var x = 0;
> var y = (x++, 10);

> x
1
> y
10```

The comma operator is confusing. It’s better to not be clever and to write two separate statements whenever you can.

### The void Operator

The syntax for the `void` operator is:

``void` `«``expr``»``

which evaluates `expr` and returns `undefined`. Here are some examples:

```> void 0
undefined
> void (0)
undefined

> void 4+7  // same as (void 4)+7
NaN
> void (4+7)
undefined

> var x;
> x = 3
3
> void (x = 5)
undefined
> x
5```

Thus, if you implement `void` as a function, it looks as follows:

````function` `myVoid``(``expr``)` `{`
`return` `undefined``;`
`}````

The `void` operator is associated closely with its operand, so use parentheses as necessary. For example, `void 4+7` binds as `(void 4)+7`.

#### What is void used for?

Under ECMAScript 5, `void` is rarely useful. Its main use cases are:

`void 0` as a synonym for `undefined`
The latter can be changed, while the former will always have the correct value. However, `undefined` is reasonably safe from being changed under ECMAScript 5, which makes this use case less important (for details, see Changing undefined).
Discarding the result of an expression
``javascript``:``void` `window``.``open``(``"http://example.com/"``)``
Prefixing an IIFE
An IIFE must be parsed as an expression. One of several ways to ensure that is by prefixing it with `void` (see IIFE Variation: Prefix Operators).

#### Why does JavaScript have a void operator?

I added the `void` operator to JS before Netscape 2 shipped to make it easy to discard any non-undefined value in a javascript: URL.

## Categorizing Values via typeof and instanceof

If you want to categorize a value, you unfortunately have to distinguish between primitives and objects (refer back to Chapter 8) in JavaScript:

• The `typeof` operator distinguishes primitives from objects and determines the types of primitives.
• The `instanceof` operator determines whether an object is an instance of a given constructor. Consult Chapter 17 for more information on object-oriented programming in JavaScript.

### typeof: Categorizing Primitives

The `typeof` operator:

``typeof` `«``value``»``

returns a string describing what kind of value `value` is. Here are some examples:

```> typeof undefined
'undefined'
> typeof 'abc'
'string'
> typeof {}
'object'
> typeof []
'object'```

`typeof` is used to distinguish primitives and objects and to categorize primitives (which cannot be handled by `instanceof`). Unfortunately, the results of this operator are not completely logical and only loosely correspond to the types of the ECMAScript specification (which are explained in JavaScript’s Types):

 Operand Result `undefined`, undeclared variable `'undefined'` `null` `'object'` Boolean value `'boolean'` Number value `'number'` String value `'string'` Function `'function'` All other normal values `'object'` (Engine-created value) JavaScript engines are allowed to create values for whom `typeof` returns arbitrary strings (different from all results listed in this table).

#### Pitfall: typeof null

````function` `isObject``(``value``)` `{`
`return` `(``value` `!==` `null`
`&&` `(``typeof` `value` `===` `'object'`
`||` `typeof` `value` `===` `'function'``));`
`}````

Trying it out:

```> isObject(123)
false
> isObject(null)
false
> isObject({})
true```

#### The history of typeof null

The type tag for objects was 000. In order to represent the value `null`, the engine used the machine language NULL pointer, a word where all bits are zero. `typeof` checked the type tag to determine the type of value, which is why it reported `null` to be an object.

#### Checking whether a variable exists

The check:

``typeof` `x` `===` `'undefined'``

has two use cases:

1. It determines whether `x` is `undefined`.
2. It determines whether the variable `x` exists.

Here are examples of both use cases:

```> var foo;
> typeof foo === 'undefined'
true

> typeof undeclaredVariable === 'undefined'
true```

For the first use case, comparing directly with `undefined` is usually a better choice. However, it doesn’t work for the second use case:

```> var foo;
> foo === undefined
true

> undeclaredVariable === undefined
ReferenceError: undeclaredVariable is not defined```

### instanceof: Checking Whether an Object Is an Instance of a Given Constructor

The `instanceof` operator:

``«``value``»` `instanceof` `«``Constr``»``

determines whether `value` has been created by the constructor `Constr` or a subconstructor. Here are some examples:

```> {} instanceof Object
true
> [] instanceof Array  // constructor of []
true
> [] instanceof Object  // super-constructor of []
true```

As expected, `instanceof` is `false` for the nonvalues `undefined` and `null`:

```> undefined instanceof Object
false
> null instanceof Object
false```

But it is also `false` for all other primitive values:

```> 'abc' instanceof Object
false
> 123 instanceof Object
false```

For details on `instanceof`, consult The instanceof Operator.

 Strictly speaking, setting an array element is a special case of setting a property.

 Thanks to Brandon Benvie (@benvie), who told me about using `void` for IIFEs.

 Thanks to Tom Schuster (@evilpies) for pointing me to the source code of the first JavaScript engine.

Next: 10. Booleans