Primitive As Object

JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects. Let’s look at the key distinctions between primitives and objects.

A primitive

An object

One of the best things about objects is that we can store a function as one of its properties.

let john = {
  name: "John",
  sayHi: function() {
    alert("Hi buddy!");
  }
};

john.sayHi(); // Hi buddy!

Like this many built-in objects already exist, such as those that work with dates, errors, HTML elements, etc. They have different properties and methods. But, these features come with a cost! Objects are “heavier” than primitives. They require additional resources to support the internal machinery. But as properties and methods are very useful in programming, JavaScript engines try to optimize them to reduce the additional burden.

There are many things one would want to do with a primitive like a string or a number. It would be great to access them as methods. But if you want to make primitive type behaves like an object you also need to make them as fast as possible. The solution looks a little bit awkward, but here it is:

The “object wrappers” are different for each primitive type and are called: String, Number, Boolean and Symbol. Thus, they provide different sets of methods.

For instance, there exists a method str.toUpperCase() that returns a capitalized string.

let str = "Hello";

alert( str.toUpperCase() ); // HELLO

Here’s what actually happens in str.toUpperCase():

So primitives can provide methods, but they still remain lightweight.

null/undefined have no methods

The special primitives null and undefined are exceptions. They have no corresponding “wrapper objects” and provide no methods. In a sense, they are “the most primitive”. An attempt to access a property of such value would give the error:

alert(null.test); // error

Constructor method for Primitive type

Some languages like Java allow us to create “wrapper objects” for primitives explicitly using a syntax like new Number(1) or new Boolean(false). In JavaScript, that’s also possible for historical reasons, but highly unrecommended. Things will go crazy in several places. For instance -

alert( typeof 1 ); // "number"

alert( typeof new Number(1) ); // "object"!

And because what follows, zero, is an object, the alert will show up:

let zero = new Number(0);

if (zero) { // zero is true, because it's an object
  alert( "zero is truthy?!?" );
}

Numbers

All numbers in JavaScript are stored in 64-bit format IEEE-754, also known as “double precision”.

You can normally write numbers as 1000000000, but you can also shorten the number using the symbol e. Here are few example -

// Something very big -
// 1e3 = 1 * 1000
// 1.23e6 = 1.23 * 1000000
let billion = 1e9;  // 1 billion, literally: 1 and 9 zeroes
alert( 7.3e9 );  // 7.3 billions (7,300,000,000)


// Something very small -
// 1e-3 = 1 / 1000 (=0.001)
// 1.23e-6 = 1.23 / 1000000 (=0.00000123)
let ms = 1e-6; // six zeroes to the left from 1, which is 0.000001;

toString

The method num.toString(base) returns a string representation of num in the numeral system with the given base. The base can vary from 2 to 36. By default it’s 10.

let num = 255;

alert( num.toString(16) );  // ff
alert( num.toString(2) );   // 11111111
alert( 123456..toString(36) ); // 2n9c

Please note that two dots in 123456..toString(36) is not a typo. If we want to call a method directly on a number, like toString in the example above, then we need to place two dots .. after it.

If we placed a single dot: 123456.toString(36), then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now goes the method.

Also could write -

alert((123456).toString(36));

Rounding

One of the most used operations when working with numbers is rounding. The inbuilt object Math provides many methods to deal with numbers -

Math.floor

The floor() method rounds a number DOWNWARDS to the nearest integer, and returns the result. If the passed argument is an integer, the value will not be rounded.

var a = Math.floor(0.60); //0
var b = Math.floor(0.40); //0
var c = Math.floor(5); //5
var d = Math.floor(5.1); //5
var e = Math.floor(-5.1); //-6
var f = Math.floor(-5.9); //-6

Math.ceil

The ceil() method rounds a number UPWARDS to the nearest integer, and returns the result. If the passed argument is an integer, the value will not be rounded.

var a = Math.ceil(0.60); // 1
var b = Math.ceil(0.40); // 1
var c = Math.ceil(5); // 5
var d = Math.ceil(5.1); // 6
var e = Math.ceil(-5.1); // -5
var f = Math.ceil(-5.9); // -5

Math.round

The round() method rounds a number to the nearest integer.

var a = Math.round(2.60); // 3
var b = Math.round(2.50); // 3
var c = Math.round(2.49); // 2
var d = Math.round(-2.60); // -3
var e = Math.round(-2.50); // -2
var f = Math.round(-2.49); // -2

Math.trunc

The trunc() method returns the integer part of a number. This method will NOT round the number up/down to the nearest ingeger, but simply remove the decimals.

Math.trunc(8.76); // 8
Math.trunc(-3.76); // -3

Math.random()

Return a random number between 0 and 1.

alert( Math.random() ); // 0.1234567894322
alert( Math.random() ); // 0.5435252343232
alert( Math.random() ); // ... (any random numbers)

If you want to get random number between 1 to 10, then multiply the number by 10 and then add 1 :

Math.floor((Math.random() * 10) + 1);

Math.max(a, b, c, ...)

Returns the greatest from the arbitrary number of arguments.

alert( Math.max(3, 5, -10, 0, 1) ); // 5

Math.min(a, b, c...)

Returns the smallest from the arbitrary number of arguments.

alert( Math.min(1, 2) ); // 1

Math.pow(n, power)

Returns n raised the given power

alert( Math.pow(2, 10) ); // 2 in power 10 = 1024

toFixed

The method toFixed(n) rounds the number to n digits after the point and returns a string representation of the result.

let num = 12.34;
alert( num.toFixed(1) ); // "12.3"

let num = 12.36;
alert( num.toFixed(1) ); // "12.4"

Please note that result of toFixed is a string. If the decimal part is shorter than required, zeroes are appended to the end:

let num = 12.34;
alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits

Infinity and NaN : isFinite and isNaN

These are special number.

They belong to the type number, but are not “normal” numbers, so there are special functions to check for them:

alert( NaN === NaN ); // false

alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true

isFinite(value) converts its argument to a number and returns true if it’s a regular number, not NaN/Infinity/-Infinity:

alert( isFinite("15") ); // true
alert( isFinite("str") ); // false, because a special value: NaN
alert( isFinite(Infinity) ); // false, because a special value: Infinity

Sometimes isFinite is used to validate whether a string value is a regular number. Please note that an empty or a space-only string is treated as 0 in all numeric functions including isFinite.

isFinite(" "); // true
isFinite("0"); // true

Object.is : Strict Equality Check

There is a special built-in method Object.is that compares values like ===, but is more reliable for two edge cases:

Object.is(3, 3); // true
Object.is(100.5678, 100.5678); // true
Object.is(3, 5); // false
Object.is(true, false); // false
Object.is(true, true); // true
Object.is(NaN, NaN); // true
Object.is(Infinity, Infinity); // true

This way of comparison is often used in JavaScript specification. When an internal algorithm needs to compare two values for being exactly the same, it uses Object.is