11+ JavaScript Features You’ve Probably Never Used

11+ useful JavaScript features you might have missed.

Chidume Nnamdi 🔥💻🎵🎮
Bits and Pieces

--

⚠ Important ⚠

Most of the features described in this post have been deprecated and some have been forbidden by EcmaScript from being used. They are still commomly found in many libraries, so it is worth learning them.

This post is for information only.

1. Tagged Template Literals

taggingThis`Hey!!, I'm  ${name} !!`

If you’ve ever used styled-components in React, you’ve used tagged template literals.

Tagged template literals give us more control over the parsing of our literals. It allows us to parse template literals with a function.

taggingThis`Hey!!, I'm  ${name} !!`

The taggingThis is a function. The first argument of a tag function contains an array of the string values, the remaining argument is related to expressions.

function taggingThis(strings, ...vals) {
//...
}
taggingThis`Hey!!, I'm ${name} !!`

The strings argument will hold [ "Hey!!, I'm ", ' !!' ] while the rest of the arguments are passed into the array, vals[ 'Nnamdi' ].

In this taggingThis the function we can manipulate the string and return something different.

function taggingThis(strings, ...vals) {
return strings[0] + vals[0] + strings[1]
}
const name = "Nnamdi"
taggingThis `Hey!!, I'm ${name} !!` // Hey!!, I'm Nnamdi !!

Tagged literals with styled-components (shared with Bit.dev):

2. Comma operator

, is an operator that separates expressions and returns the last expression in the chain.

let expr = (99, 88, 77)
expr // 77

We have three primary expressions 99, 88 and 77. All are evaluated and the last is assigned to expr.

We see this in for loops:

for(let i = 0, ii = 1; i< 10; i++, ii--) { ... }

This comes in handy when we want to write short lambda functions:

const lb = (a, b, arr) => (arr.push(a*b), a*b)

There are two statements here, the first push the multiplication result to the array arr and the second multiples a and b. The result of the second is what is returned to the caller.

It is also useful with the ternary operator since, same as the short lambda syntax, it only accepts expressions rather than statements

3. with

⚠Caution⚠

The use of the with statement is generally discouraged, as it was deprecated. It is completely forbidden in strict mode. Turns out, with blocks adds some performance and security problems in the language.

with is a keyword in JS. It is used to extend the scope chain of statement(s)

It is used like this:

with(expression)
statement
// ORwith(expression) {
statement
statement
...
}

The expression is evaluated and a scope is created around the expression. The expression and the parent scope of the with statement are available within the brackets.

const a = 45
let b = 8
var f = 909
with(f) {
log(f, b, a) // 909 8 45
}

with encloses f within the scope chain. f and other variables declared outside the with block will be visible with the with block body.

Note, let and const variables declared with a with block is only visible within the block, it is not visible outside the with block.

with(f) {
log(f, b, a) // 909 8 45
let withinF = 20
}
log(withinF) // undefined

Trying to access withinF will throw a ReferenceError because the withinF variable is only present in the with block

As awesome this is, with is advised to be avoided.

More on this:

4. in

in is a keyword that is used to check for the presence of a property in an object. We have used it in for..in loop without realizing that the in is a keyword :)

in will return true if a property is present on the object, and will return false if otherwise.

const o = {
prop: 90
}
log("prop" in o) // true

See, in is used standalone without the for...in loop.

It will check if the “prop” is available as property in the o object. It returns true because we have “prop” defined in o.

If we check against undefined property,

const o = {
prop: 90
}
log("prop1" in o) // false

It logs false. Yes, because “prop1” is not available as property in the o object.

Have you used this? 😁

More on this:

5. Array constructor

Do you know that we can define an array without the traditional method?

const arr = [90,88,77]

How?

We use the Array constructor.

const arr = new Array(90, 88, 77)

The arrangement of the params passed to the constructor will form the basis of their indexes.

90 being the first param will be at index 0, 88 the second will be at index 1 and 77 last will be at index 2.

arr[0] // 90
arr[1] // 88
arr[2] // 77

Using the new Array(...) is the same thing as using the array literal.

So this,

const arr = new Array(90, 88, 77)

is the same thing as doing this:

const arr = [90, 88, 77]

Some people think that there is a drawback or inconsistency when using this Array constructor feature:

Creating an array as above using the Array constructor with new, applies when the arguments to the constructor new Array() is greater or equal to 2.

Doing this

const arr = new Array(90, 88, 77)

will create an array [90, 88, 77]. This is becuase the arguments to new Array(..) are 3, that is they are >= 2.

Passing one argument to the new Array(...), will cause the JS engine to allocate space for an array the size of the argument passed.

const arr = new Array(6)

This will create an array with 6 items or elements and the length will be 6:

const arr = new Array(6)
arr // [ <6 empty items> ]
arr.length // 6

So doing const arr = new Array(6) is same as doing this:

const arr = [, , , , , ]arr // [ <6 empty items> ]
arr.length // 6

I wouldn’t agree if you say this is JS inconsistent or crazy feature. It is in the EcmaScript Spec.

See, it is not inconsistency. It is all described there in the specs. We should always read the specs of any language first before giving any conclusion.

6. Function constructor

Do you know that we can define a Function using the Function constructor.

You don’t understand, right? Lemme make it clearer. In JS we define functions like this:

const mul = (a, b) => a * b

// OR

function mul(a, b) {
return a * b
}

// OR

const mul = function(a, b) {
return a * b
}

We can still do this using the Function:

const mul = new Function("a", "b", "return a * b")

😁

The params passed to Function forms the arguments and body of the function. The variable mul becomes the function name.

The last param will be the body of the function, while the params before the last param will become the function’s arguments.

See, in the mul. Params “a” and “b” are the params the function will receive and the “return a * b” param is the body of the function. It multiplies “a” and “b” and returns the result.

To call the function we write the variable with the brackets “mul(…)” passing in the parameters:

const mul = new Function("a", "b", "return a * b")

log(mul(7, 8)) // 56

According to MDN Docs:

Calling the constructor directly can create functions dynamically, but suffers from security and similar (but far less significant) performance issues to eval. However, unlike eval, the Function constructor creates functions which execute in the global scope only.

More on this:

7. Destructuring Array

We can destructure elements in an array by using the index number of the elements.

const arr = [99, 88, 77]

The elements 99, 88, 77 have indexes 0, 1, 2. To get element 99 from the arr array, we pass it as a property to arr,

arr[1]

just like we do on objects:

let o = {
prop: 99
}
o[prop] // 99

We can destructure prop from o like this:

const {prop} = o
prop // 99

So we can too on arrays:

const arr = [99, 88, 77]

const { 1: secA } = arr
secA // 88

const { 0: firstA, 1: secA, 2: thirdA } = arr

firstA // 99
secA // 88
thirdA // 77

See, we used the index number to extract the elements. The indexes are properties that define the position of the elements in the array. So this,

const arr = [99, 88, 77]

is equivalent to this:

const arr = {
0: 99,
1: 88,
2: 77,
length: 3
}

Arrays are objects, too, which is why object destructuring works on them, but there is also a special array destructuring syntax:

const [first, second, third] = arr;

avoid having to know the specific positional information in arrays (what the start, end indices are) if possible

8. Reducing Array contents using the length property

Arrays can be reduced from manipulating the length property.

The length property in an array indicates the number of elements in the array.

const arr = [99, 88, 77]
arr.length // 3

Decreasing the length property will make the JS engine reduce the elements to equal the value of the length property.

const arr = [99, 88, 77]
arr.length // 3
arr.length = 1
arr // [ 99 ]

The length property of arr was changed to 1, so the elements were reduced from the right to make it equal the value of the length property.

If we increase the length property, the JS engine will add elements (undefined ones) to make the number of the elements in the array to tally up to the value of the length property.

const arr = [99, 88, 77]
arr.length // 3
arr.length = 1
arr // [ 99 ]

arr.length = 5
arr // [ 90, <4 empty items> ]

The elements in the arr were only one, then we increased the length to 5, so 4 more items were added to make the contents 5 in number.

9. Arguments

We have used arguments to get arguments passed to a function. The cool thing about this is that we can get the arguments passed to a function with the arguments object without explicitly defining the arguments variables in the function:

function myFunc() {
arguments[0] // 34
arguments[1] // 89
}

myFunc(34,89)

The arguments object is array-indexed. That is, the properties are numbers and so can be accessed via key-references.

The arguments object is instantiated from the Arguments class, which has some cool properties.

arguments.callee.name This refers to the name of the function currently being called.

function myFunc() {
log(arguments.callee.name) // myFunc
}

myFunc(34, 89)

arguments.callee.caller.name Refers to the name of the function that called the currently executing function.

function myFunc() {
log(arguments.callee.name) // myFunc
log(arguments.callee.caller.name) // myFuncCaller
}

(function myFuncCallee() {
myFuncCaller(34, 89)
})()

This is useful in variadic functions particularly

More on this:

10. Skip the brackets

Do you know that we can skip the brackets () when instantiating an object?

For example:

class D {
logger() {
log("D")
}
}

// Normally, we do this:
(new D()).logger() // D

// Also, we can skip the ():
(new D).logger() // D
// and it still works

The brackets are optional, even in built-in classes:

(new Date).getDay()
(new Date).getMonth()
(new Date).getYear()

11. void operator

void is a keyword in JS that evaluates a statement and returns undefined.

Example:

class D {
logger() {
return 89
}
}

const d = new D

log(void d.logger()) // undefined

See, the logger method should return 89, but the void keyword nullifies and returns undefined instead.

I’ve read that undefined could be assigned another value before, which falsified its semantics. So the void operator was used to ensure you got a real undefined. Also for minimization purposes.

More on this:

12. Function property

We can set properties in functions like this:

function func() {
func.prop1 = "prop1"
}
func.prop2 = "prop2"

Functions are objects so the above is a valid thing to do. This Function property will be a static property to all instances of the Function when used a object

const j1 = new func()
const j2 = new func()
j1.prop1 // prop1
j2.prop1 // prop1
j1.prop1 = "prop1 changed"
j2.prop1 // prop1 changed

or it will be a global property when used as a function.

function func() {
func.prop1 === undefined ? func.prop1 = "yes" : null
if(func.prop1 === "yes")
log("Prop with Yes")
if (func.prop1 == "no")
log("Prop with No")
}
func() // Prop with Yes
func.prop1 = "no"
func() // Prop with No

13. Inheritance via __proto__

_proto_ is a way to inherit properties from an object in JavaScript. __proto__ a property of Object.prototype is an accessor property that exposes the [[Prototype]] of the object through which it is accessed.

This __proto__ sets all properties of the object set in its [[Prototype]] to the target object.

Let’s look at a an example:

// proto.jsconst log = console.logconst obj = {
method: function() {
log("method in obj")
}
}
const obj2 = {}
obj2.__proto__ = obj
obj2.method()

We have two object literals: obj and obj2. obj has a method property, method. obj2 is an empty object literal ie it has no properties.

Moving down, we access the __proto__ of obj2 and set it to obj. This will copy all the properties of the obj accesssible via Object.prototype to obj2. That's why we can call the method on obj2 without getting an error despite not being defined there.

$ node proto
method in obj

obj2 has inherited the properties of obj, so the method method property will be available in its properties.

proto is used on Objects e.g object literal, Object, Array, Function, Date, RegEx, Number, Boolean, String.

14. Unary + Operator

The unary + operator converts its operand to Number type.

+"23" // 23
+{} // NaN
+null // 0
+undefined // NaN
+{ valueOf: () => 67 } // 67
+"nnamdi45" // NaN

This comes in handy when we want a quick conversion of variables to Number.

15. Unary — Operator

The unary — operator converts its operand to Number type and then negates it.

This operator inverts the result of the unary + operator. First, it converts the operand to its Number value, then negates the value.

-"23" // -23

What happens here is that, the strign “23” will converted to its Number type which will give 23. Then, this positive number will be converted to its negative form which is -23

-{} // NaN
-null // -0
-undefined // NaN
-{ valueOf: () => 67 } // -67
-"nnamdi45" // NaN

If the result of the conversion to number value is NaN, negation will not be applied.

Negating +0 produces -0, and negating -0 produces +0.

- +0 // -0
- -0 // 0

16. Exponentiation ** operator

This operator is used to find the exponent of a number. Like finding the power of a number raised to a certian degree.

In Math, if we 2 raise to the power of 3 (i.e finding the exponent of 2), means multiplying 2 thrice:

2 * 2 * 2

We can do the same in JS using the ** operator:

2 ** 3 // 8
9 ** 3 // 729

Conclusion

😀 So many awesome features in JS. More features are coming, I’ll be updating this post, as they come in.

If you have or found any feature(s) of JS that are rarely used, free free to drop them in the comments. I’ll be so glad to know them 😀

Get my eBook

I have written an eBook that explains a lot of JavaScript concepts in simpler terms with reference to the EcmaSpec as a guide:

Learn More

--

--

JS | Blockchain dev | Author of “Understanding JavaScript” and “Array Methods in JavaScript” - https://app.gumroad.com/chidumennamdi 📕