JavaScript data types, weakness is a state of mind!

David Moreno
Frontend Weekly
Published in
5 min readApr 15


JavaScript is considered a weak typed but fast language that offers a set of primitive types (String, Number, Boolean, undefined, Symbol, BigInt) in its host environment, to handle data in our applications, along with some wrappers to manipulate it.

As a frontend developer I firmly believe that you must master JavaScript (commonly known as Vanilla JavaScript) before starting to learn any of its frameworks like Vue, Angular or React. If you dominate JavaScript, it will be easier to learn any framework for sure.

JavaScript, as many other languages, comes with a set of predefined features you can use to start writing your application. That world where those things already exist is often called the host environment. In the frontend scope, it’s the browser.

When we create applications, most of the time we want to work with data and information, of course. Not only to read it but also to manipulate it. Nonetheless, how can we tell our application that we want to make math operations, process texts or make a decision? Well, that’s where data types provided by the host environment come into action.

Disclaimer: JavaScript is known as a weakly typed language (actually, is a dynamic type language). There’s no official technical definition nor a scale of strength for programming languages, but generally it refers to how strict the language is with its typing rules.

Yes, JavaScript can sometimes produce strange results due to some unpredictable implicit conversions or reassignments between values of different types at runtime. When programmers come from other stronger typed languages, they’re always surprised and can’t believe how permissive JavaScript is when manipulating data types. They even think and openly say that JavaScript is bullshit!

Well… I admit that this “weakness” might lead to very strange issues that could be easily detected at compile time with stricter type validations. But, usually these kinds of languages are faster and have a very good performance in machines that don’t have the DeLorean engine in its CPUs (like average PCs and/or mobile devices).

If you have TypeScript plus right plugins and extensions in your IDE plus high coverage in your tests, who cares when those issues are caught? weakness is a state of mind!

Without further ado, the original set of primitive data types provided by JavaScript are: Numbers, Strings, Booleans and Undefined. The rest of the values are Objects: Null, Arrays, custom objects, etc (Symbol and BigInt primitives were introduced in ES2015+, aka ES6).

typeof NaN // number
typeof '123' // string
typeof false // boolean
typeof undefined // undefined
typeof function myFunction(){} // is an object, despite it returns "function"
typeof [] // object
typeof {} // object
typeof null // object

However, one reason why they are called primitives is because they cannot be decomposed into simpler data types and cannot be changed or manipulated.

That’s why the language also provides wrapper classes in the host environment. By instantiating these wrapper classes, the language enables us to simulate properties and methods over the primitives. Note that the object is automatically created and lives for only one line of code.

So, the following:

const primitiveString = 'any primitive string';
const subStr = primitiveString.substring(4);
console.log(subStr); // primitive string

Is basically this behind the scenes:

const primitiveString = 'any primitive string';
const temporalWrapper = new String(primitiveString);
const subStr = temporalWrapper.substring(4);
temporalWrapper = null;
console.log(subStr); // primitive string

And that’s why it does not work:

const primitiveString = 'any primitive string'; = 'another string';
console.log(; // undefined

…but it does:

let primitiveString = 'any primitive string';
primitiveString = 35;
console.log(primitiveString); // 35

Some considerations with primitives are:


  • It’s a value of 64-bits. we can represent (2).pow(64) different numbers. One bit indicates the sign (+/-) and some others store the decimal position.
  • There’s no separated Integer type.
  • Special values: Infinity, -Infinity, Nan.
  • NaN is the only numeric value in JavaScript that is not equal to itself.
  • Calculations with decimals are generally not precise.
1 === 1.0 // true
NaN === NaN // false
0.1 + 0.2 // 0.30000000000000004
3.1416 * Infinity // Infinity
3.1416 / Infinity // 0


  • It represents text, content is enclosed in quotes (single or double).
  • Whenever a backslash \ is found inside quoted text, it indicates that the character after it has a special meaning. This is called escaping the character.
  • When comparing strings, it goes over them from left to right, comparing the (Unicode standard) numeric codes of the characters one by one. Uppercase letters are always ‘less’ than lowercase ones.
console.log('she said: "hello"') // she said: “hello”
console.log('It\'s alright') // It’s alright
'Z' < 'a' // true, (90 < 97)


  • It has just two values: true and false
  • When converting strings and numbers to boolean: 0, NaN, and the empty string ‘’ count as false, while all the other values count as true.
  • Null & undefined are falsy values as well.
console.log(0 == false); //true 
console.log(‘’ == false); //true
console.log(‘’ == 0); //true

Null & Undefined

  • Denote the absence of a meaningful value.
  • Undefined means a variable has been declared but has not yet been assigned a value.
  • Null is an assignment value. It can be assigned to a variable as a representation of no value.
var undefinedVar;
let undefinedLet;
const undefinedConst; // Throws error
console.log(undefinedVar); // undefined
console.log(undefinedLet); // undefined

var nullVar = null;
console.log(nullVar); // null
console.log(typeof nullVar); // object
let nullLet = null;
const nullConst = null;
console.log(nullLet); // null
console.log(typeof nullConst); // null

null === undefined // false
null == undefined // true
null === null // true
null = 'value' // ReferenceError
undefined = 'value' // 'value'


  • Values of the type Object are arbitrary collections of properties, and we can add or remove these properties as we please.
  • Both value.x and value[x] access a property on value, but not necessarily the same property. The difference is in how x is interpreted. Whereas value.x fetches the property of value named x, value[x] tries to evaluate the expression x and uses the result as the property name.
  • Objects can contain other objects, so they can easily represent tree or graph structures.
  • Arrays are just a kind of object specialized for storing sequences of things. The elements in an array are stored in properties. Because the names of these properties are numbers and we often need to get their name from a variable, we have to use the bracket syntax to access them.
  • Since Functions are objects, they can be used like any other value. Functions can be stored in variables, objects, and arrays. Functions can be passed as arguments to functions, and functions can be returned from functions.

I won’t cover Symbols nor BigInt in this article.

Finally, thanks to the flexibility that we have when handling data types in JavaScript, it’s easier to make decisions in the code with some other techniques like Coercion or Short circuit evaluation. If you want to go deeper with these topics, just search them in medium.

And there we have it. I hope you have found this useful. Thank you for reading.



David Moreno
Frontend Weekly

Frontend Developer from LATAM, passionate with best practices for web applications.