You might have come across things like i++, –i in loops or ** !** when writing conditions. Ever wondered how these operations work? Well, these are unary operators and we are going to take an in-depth look into how they work.
What is an operator?
Mathematically, an operation is a calculation on one or more values called operands mapping to an output value. An operator is a symbol/sign that maps operands to output values.
What is an unary operator?
A unary operator is one that takes a single operand/argument and performs an operation.
A unary operation is an operation with only one operand. This operand comes either before or after the operator.
Unary operators are more efficient than standard JavaScript function calls. Additionally, unary operators can not be overridden, therefore their functionality is guaranteed.
Summary of all unary operators
Operator | Explanation |
---|---|
Unary plus (+) | Tries to convert the operand into a number |
*Unary negation (-) * | Tries to convert the operand into a number and negates after |
Logical Not (!) | Converts to boolean value then negates it |
Increment (++) | Adds one to its operand |
Decrement (–) | Decrements by one from its operand |
Bitwise not (~) | Inverts all the bits in the operand and returns a number |
typeof | Returns a string which is the type of the operand |
delete | Deletes specific index of an array or specific property of an object |
void | Discards a return value of an expression. |
Unary plus (+)
This operator precedes the operand and tries to convert it to a number.
It can convert all string representations of numbers, boolean values(true and false) and null to numbers. Numbers will include both integers, floats, hexadecimal, scientific (exponent) notation and Infinity.
If the operand cannot be converted into a number, the unary plus operator will return NaN.
Examples:
+3 // returns 3
+'-3' // returns -3
+'3.14' // returns 3.14
+'3' // returns 3
+'0xFF' // returns 255
+true // returns 1
+'123e-5' // returns 0.00123
+false // returns 0
+null // returns 0
+'Infinity' // returns Infinity
+'infinity' // returns NaN
+function(val){ return val } // returns NaN
The illustration above clearly shows how the + operator will behave when applied to different data types.
- Numbers will not be altered.
- A string notation of a number e.g ‘3’ is converted to that number (3).
- Boolean value true is converted to a 1 and false to 0.
- Other types e.g functions and objects are converted to NaN.
Note
An object can only be converted if it has a key valueOf and it’s function returns any of the above types.
+{
valueOf: function(){
return '0xFF'
}
}
//returns 255
Unary negation (-)
It also precedes the operand and converts non-numbers data types to numbers like unary plus, however, it performs an additional operation, negation.
Unary plus is considered the fastest and preferred way of making conversions because it doesn’t perform any additional operation.
Both the unary negation and plus perform the same operation as the Number() function for non-numbers.
Examples:
-3 // returns -3
-'-3' // returns 3
-'3.14' // returns -3.14
-'3' // returns -3
-'0xFF' // returns -255
-true // returns -1
-'123e-5' // returns -0.00123
-false // returns -0
-null // returns -0
-'Infinity' // returns -Infinity
-'infinity' // returns NaN
-function(val){ return val } // returns NaN
-{ valueOf: function(){
return '0xFF'
}
} //returns -255
Logical Not (!)
This operator comes before the operand. It converts the operand into it’s boolean equivalent before negating it.
Examples:
!false // returns true
!NaN // returns true
!0 // returns true
!null // returns true
!undefined // returns true
!"" // returns true
!true // returns false
!-3 // returns false
!"-3" // returns false
!42 // returns false
!"42" // returns false
!"foo" // returns false
!"true" // returns false
!"false" // returns false
!{} // returns false
![] // returns false
!function(){} // returns false
The above illustration demonstrates how logical not returns ** false** if the operand can be converted to true, if not it returns false.
You can use double negation(!!)
Let us take a look at a more awesome example:
!!'hi' === true // returns true
!!1 === true // returns true
!!0 === false // returns true
Why true?
So we execute from right to left.
!'hi' //returns false
Then:
!false //returns true
Thus:
true === true //returns true
Increment (++)
This operator adds one to its operand and returns the result.
It can be used as a postfix or prefix operator.
- Postfix : – meaning the operator comes after the operand(y++). This returns the value before incrementing.
- Prefix: – the operator comes before the operand (++y). Using it as a prefix, returns the value after incrementing.
Examples:
Postfix
x = 4 // x=4
y = x++ // y = 4 and x = 5
// y is set to the value before incrementing and it adds 1 to x
// Be careful about resetting values when using postfix
var a = 5 // a = 5
a = a++ // a = 5
// a is set to the value before incrementing
Prefix
x = 4 // x=4
y = ++x // y = 5 and x = 5
// y is set to the value after incrementing and it adds 1 to x
var a = 5 // a = 5
a = ++a // a = 6
// a is set to the value after incrementing
Decrement (–)
The decrement operator subtracts one from its operand.
It returns a value before decrementing if it is postfix. Prefixing it returns the value after decrementing.
Examples:
Postfix
var a = 5 // a = 5
a = a-- // a = 5
// a is set to the value before incrementing
x = 4 // x=4
y = x-- // y = 4 and x = 3
// sets y to the value before decrementing and it removes 1 from x
Prefix
var a = 5 // a = 5
a = --a // a = 4
// a is set to the value after incrementing
x = 4 // x=4
y = --x // y =3 and x = 3
// sets y to the value after incrementing and it adds 1 to x
Bitwise not (~)
Performs a binary NOT operation, by inverting all the bits in the operand and return a number.
A bitwise not on a number results in: -(x + 1).
Examples:
~2 //returns -3
~'2' //returns -3
~'-3' // returns 2
-'-3.14' // returns 2
~'-3.54' // returns 2
~'0xFF' // returns -256
~true // returns -2
~'123e-5' // returns -1
~false // returns -1
~null // returns -1
~'Infinity' // returns -1
~'infinity' // returns -1
~function(val){ return val } // returns -1
~{ valueOf: function(){
return '0xFF'
}
} //returns -256
The table below takes a deeper look into how this operation is performed.
(base 10) | (base 2) | Not (base 2) | Not (base 10) |
---|---|---|---|
2 | 00000010 | 11111101 | -3 |
1 | 00000001 | 11111110 | -2 |
0 | 00000000 | 11111111 | -1 |
-1 | 11111111 | 00000000 | 0 |
-2 | 11111110 | 00000001 | 1 |
-3 | 11111101 | 00000010 | 2 |
typeof
This operator comes before the operand. It returns a string indicating the data type of the operand.
Examples:
typeof 2 // returns 'number'
typeof -3.14 // returns 'number'
typeof 0xFF // returns 'number'
typeof 123e-5 // returns 'number'
typeof true // returns 'boolean'
typeof false // returns 'boolean'
typeof null // returns 'object'
typeof Infinity // returns 'number'
typeof '2' // returns 'string'
typeof '-3' // returns 'string'
typeof 'infinity' // returns 'string'
typeof Date() // returns 'string'
typeof [1,2,3] // returns 'object'
typeof {hi: 'world'} // returns 'object'
typeof function(val){ return val } // returns 'function'
typeof { valueOf: function(){
return '0xFF'
}
} // returns 'object'
typeof undefined // returns 'undefined'
typeof hi // returns 'undefined'
typeof NaN // returns 'number'
typeof new Date() // returns 'object'
typeof /ab+c/ // returns 'object'
typeof new RegExp('ab+c') // returns 'object'
typeof document // returns 'undefined'
delete:
It also comes before the operand. It deletes values of a specific index of an array and a specific property of an object.
It returns true if it successfully deleted the property or if the property does not exist.
It returns** false** if it fails to delete an item.
Delete does not have any effect on both functions and variables. Let’s look at the following examples.
// Deleting a variable
var hi = 1;
delete hi; // returns false
console.log(hi); // returns 1
// Deleting a function
function yo(){ };
delete yo; // returns false
console.log(yo); // returns function foo(){ }
// Deleting an object
var pub = {bar: '1'}
delete pub // returns false
console.log(pub); // returns {bar: '1'}
//Deleting an array
var code = [1,1,2,3,5]
delete code // returns false
console.log(code); // [1,1,2,3,5]
Objects
As earlier stated, it deletes the property or the whole object.
Examples:
// Deleting a property with the literal notation
var fruits = {1: 'apple', 2: 'mango'}
delete fruits[1] // returns true
console.log(fruits); // returns { '2': 'mango' }
console.log(fruits[1]); // returns undefined
// Deleting a property with the dot notation
var pub = { bar: "42" };
delete pub.bar; // returns true
console.log(pub); // returns {}
// Deleting a property that does not exist
var lunch = { fries: 1 };
delete lunch.beans; // returns true
console.log(lunch); // returns { fries: 1 }
// Deleting a non-configurable property of a predefined object
delete Math.PI; // returns false console.log(Math.PI); // returns 3.141592653589793
Non-Configurable properties
Delete has no effect on an object property that is as non-configurable. It will always return false.
In strict mode, this will raise a SyntaxError.
Examples:
// When Non Configurable
var Person = {};
Object.defineProperty(Person, 'name', { value: 'Scot', configurable: false })
// Defines an object property and sets it to non-configurable
console.log(Person.value); // returns 'Scot'
delete Person.value // returns false
console.log(Person.value); // returns 'Scot'
// When configurable
var b = {};
Object.defineProperty(Person, 'name', { value: 'Scot', configurable: true })
console.log(b.value); // returns 'Scot'
delete b.value // returns true
console.log(b.value); // returns undefined
Read more about defineProperty()
var, let and const create non-configurable properties that cannot be deleted with the delete operator:
Example:
var num = 1;
// We can access this global property using:
Object.getOwnPropertyDescriptor(window, 'num') // returns { value: 'XYZ',
// writable: true,
// enumerable: true,
// configurable: false } delete num; // returns false
// Node
Object.getOwnPropertyDescriptor(global, 'num')
// returns { value: 'XYZ',
// writable: true,
// enumerable: true,
// configurable: false }
// regular objects
var lunch = { fries: 1 }; Object.getOwnPropertyDescriptor(lunch, 'fries')
// returns { value: 1,
// writable: true,
// enumerable: true,
// configurable: true }
Notice that the var keyword is marked as non-configurable
Arrays
Arrays are considered type object in javascript. Thus this method will work on them.
Examples:
// Deleting values of an array index
var lol=[20,30,40];
console.log(lol.length); // returns 3
delete lol[2] // returns true
console.log(lol); // returns [ 20, 30, ]
console.log(lol[2]); // returns undefined
console.log(lol.length); // returns 3
Note
The delete operator will only delete the value and *not the index *of the array. It will leave the value of that particular index as undefined. This is why the length does not change.
strict mode
In strict mode, delete throws a SyntaxError due to the use of direct reference to a variable, a function argument or a function name.
‘use strict’
var fruits = {1:'mango', 2:'apple'};
delete fruits;
// Output: Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
function Person() {
delete name; // SyntaxError
var name; }
function yo() {
}
delete yo; // SyntaxError
Here are a few pointers to always consider when using delete:
Trying to delete a property that does not exist, delete will return true but will not have an effect on the object.
Delete only affects object own properties. This means if a property with the same name exists on the object’s prototype chain, then delete will not affect it. After deletion, the object will use the property from the prototype chain.
Variable declared var,_ let_ and const cannot be deleted from the global scope or from a function’s scope.
- Meaning:- Delete cannot delete any functions in the global scope or in the function scope.
- Delete works on functions which are part of an object (apart from the global scope).
Non-configurable properties cannot be removed.
Delete does not work on any of the built-in objects like Math, Array, Object or properties that are created as non-configurable with methods like Object.defineProperty().
Void operator:
It precedes an operation. It discards the return value of an expression, meaning it evaluates an expression but returns undefined.
Void operator’s main purpose is to return undefined. The void operator specifies an expression to be evaluated without returning a value.
The void operator is used in either of the following ways:
void (expression)
void expression
Note:
The void operator is not a function, so () are not required, but it is good style to use them according to MDN
Example:
void 0 // returns undefined
var hi = function () {
console.log('Yap')
return 4;
}
var result = hi() // logs 'Yap' and returns 4
console.log(result); // returns 4
var voidResult = void (hi()) // logs 'Yap' and returns undefined
console.log(voidResult); // returns undefined
The void operator can be used to specify an expression as a hypertext link. The expression is evaluated but is not loaded in place of the current document.
Some more examples
<a href="https://www.digitalocean.com/community/tutorials/javascript:void(0)">Click here to do nothing</a>
The code above creates a link that does nothing when a user clicks it. This is because void(0) evaluates to undefined.
<a href="https://www.digitalocean.com/community/tutorials/javascript:void(document.form.submit())">
Click here to submit</a>
The code creates a link that submits a form when the user clicks it.
Conclusion
Always consider the order of operations when dealing with more than one operator. This is good practice in mitigating unforeseen bugs.
Here is a brief table that shows the order of precedence in operations when using Javascript. Operands on the same level have the same order of precedence.
Operator type | Operators | Example |
---|---|---|
member | . [] | [1,2,3] |
call / create instance | () new | var vehicle = new Vehicle(); |
negation/increment | ! ~ – + ++ – typeof void delete | typeof [1,2,2] |
multiply/divide | * / % | 3 % 3 |
addition/subtraction | + – | 3 + 3 |
bitwise shift | << >> >>> | 9 << 2 |
relational | < <= > >= in instanceof | [1] instanceof Array |
*equality * | == != === !== | void(0) === undefined |
bitwise-and | & | 5 & 1 |
*bitwise-xor * | ^ | 5 ^ 1 |
bitwise-or | ||
logical-and | && | x < 10 && y > 1 |
logical-or | ||
conditional | ?: | (age < 18) ? “Too young”:“Old enough” |
assignment | = += -= *= /= %= <<= >>= >>>= &= ^= | = |
*comma * | , | b = 3, c = 4 |