Briefly
In JavaScript, an object is the ancestor of all other entities. All data types and structures, except for primitives, are descendants of the object. For this reason, all descendants of the object have a set of common methods: to
, value
, and others.
How to Understand
Arrays and Functions
Object — is an entity with a set of properties. We can add, change, and delete these properties.
const programmer = { name: 'John', level: 'Junior' }programmer.mainLanguage = 'JavaScript'delete programmer.levelconsole.dir(programmer)
const programmer = { name: 'John', level: 'Junior' } programmer.mainLanguage = 'JavaScript' delete programmer.level console.dir(programmer)

If you look at an array, it also has a set of properties, but its own. For example, an array has a length, methods to work with it. Accessing an array element by index, as can be noticed, is similar to accessing a property of an object using square brackets.
const shows = ['Breaking Bad', 'The Office', 'Silicon Valley']// Property of the arrayshows.length// Get an array element,// similar to how you would with an object shows['1']shows[1]
const shows = ['Breaking Bad', 'The Office', 'Silicon Valley'] // Property of the array shows.length // Get an array element, // similar to how you would with an object shows['1'] shows[1]
The same situation applies to functions. They also have a set of properties that can be seen by outputting their information to the console.
function sum(a, b) { return a + b}// You can call a property of the functionsum.arguments// You can assign a value to a fieldsum.someField = 'value'console.dir(sum)
function sum(a, b) { return a + b } // You can call a property of the function sum.arguments // You can assign a value to a field sum.someField = 'value' console.dir(sum)
In the output, there is the property some
, which we assigned, and a set of built-in properties and methods.

This structure of arrays and functions is very similar to the structure of objects. But in fact, they are objects. This can be easily verified. Let's look at the property _
of the function sum
, described above.

If you look at the prototype property, you can notice that the current prototype is an object. Peeking into this prototype, you can see the following picture:

In this chain, there is no next prototype, which means that we have reached the very end of the chain, that is, found the ancestor. If you output any array to the console in this way, then by descending down the prototype chain, there will definitely be the prototype of the object at the end. Any entity in JavaScript inherits from the object.

Primitives
In JavaScript, there are primitive data types such as strings, numbers, or boolean values. When working with a string, you can discover that it also has properties and methods that can be accessed.
const show = 'Breaking Bad'console.log(show.length)// 12console.log(show.charAt(1))// 'r'console.log(show.toUpperCase())// 'BREAKING BAD'
const show = 'Breaking Bad' console.log(show.length) // 12 console.log(show.charAt(1)) // 'r' console.log(show.toUpperCase()) // 'BREAKING BAD'
If a string is a primitive data type, where does it get the behavior of an object? When we access a property or method of a primitive, a wrapper is created using a special constructor (autoboxing
), which is a descendant of Object
. For a string, this will be the function String
. This object has properties and methods that are invoked.
const pet = 'dog'// An object will be createdconst pet2 = new String('dog')console.log(pet === pet2)// false, because pet2 contains an objectconsole.dir(pet2)/* Will output{ 0: "d", 1: "o", 2: "g", length: 3}*/
const pet = 'dog' // An object will be created const pet2 = new String('dog') console.log(pet === pet2) // false, because pet2 contains an object console.dir(pet2) /* Will output { 0: "d", 1: "o", 2: "g", length: 3 } */
For other data types, there are similar functions: Number
for numbers, Boolean
for boolean values. All these functions are also descendants of the object.
The main difference between objects (arrays, functions) and primitives is that primitives are immutable. Trying to change or add properties to a primitive does nothing.
const cat = 'Boris'// The property won't be addedcat.color = 'red'// It won't change anything eitherdelete color.lengthconst cats = ['Boris', 'Vasya', 'Murzik']// Now the array has a length of five elementscats.length = 5// A field has been addedcats.someField = 'value'console.dir(cats)/*{ 0: "Boris", 1: "Vasya", 2: "Murzik", someField: "value", length: 5}*/
const cat = 'Boris' // The property won't be added cat.color = 'red' // It won't change anything either delete color.length const cats = ['Boris', 'Vasya', 'Murzik'] // Now the array has a length of five elements cats.length = 5 // A field has been added cats.someField = 'value' console.dir(cats) /* { 0: "Boris", 1: "Vasya", 2: "Murzik", someField: "value", length: 5 } */
Do not confuse a primitive with an object created through a constructor for that primitive:
const cat = new String('Boris')cat.color = 'black'// It will be added, as cat holds an object, not a string
const cat = new String('Boris') cat.color = 'black' // It will be added, as cat holds an object, not a string
How It Is Written
Fields and methods of objects and arrays can always be invoked: through a variable and inline, meaning without using a variable.
const array = [1, 2, 3, 4]console.log(array[1])// 2const pos = 3console.log(array[pos])// 4console.log(array.map(a => a + 1))// [2, 3, 4, 5]const f = 'map'console.log(array[f](a => a + 1))// [2, 3, 4, 5]const obj = { name: 'Boris', color: 'red' }console.log(obj.color)// 'red'console.log(obj['name']);// 'Boris'const age = Object.assign(obj, { name: 'Vasya', age: 30}).ageconsole.log(age)// 30
const array = [1, 2, 3, 4] console.log(array[1]) // 2 const pos = 3 console.log(array[pos]) // 4 console.log(array.map(a => a + 1)) // [2, 3, 4, 5] const f = 'map' console.log(array[f](a => a + 1)) // [2, 3, 4, 5] const obj = { name: 'Boris', color: 'red' } console.log(obj.color) // 'red' console.log(obj['name']); // 'Boris' const age = Object.assign(obj, { name: 'Vasya', age: 30 }).age console.log(age) // 30
Almost all primitives can also have methods accessed without a variable:
true.toString()// 'true'Infinity.toString()// 'Infinity''hello world'.toString()// 'hello world'Symbol('tag').toString()// 'Symbol(tag)'9007199254740991n.toString()// '9007199254740991'
true.toString() // 'true' Infinity.toString() // 'Infinity' 'hello world'.toString() // 'hello world' Symbol('tag').toString() // 'Symbol(tag)' 9007199254740991n.toString() // '9007199254740991'
However, in the case of numbers, you can get a syntax error because the dot is interpreted as part of the number itself:
42.toString()// Uncaught SyntaxError:// Invalid or unexpected token
42.toString() // Uncaught SyntaxError: // Invalid or unexpected token
To avoid this, you can use two dots, wrap the expression in parentheses, or call the wrapper of the primitive type:
42..toString()// '42'(42).toString()// '42'Number(42).toString()// '42'
42..toString() // '42' (42).toString() // '42' Number(42).toString() // '42'
Calling methods or properties will not work on null
and undefined
:
null.toString()// Uncaught TypeError:// Cannot read property 'toString' of nullnull.valueOf()// Uncaught TypeError:// Cannot read property 'valueOf' of nullnull.length// Uncaught TypeError:// Cannot read property 'length' of nullundefined.toString()// Uncaught TypeError:// Cannot read property 'toString' of undefinedundefined.valueOf()// Uncaught TypeError:// Cannot read property 'valueOf' of undefinedundefined.length// Uncaught TypeError:// Cannot read property 'length' of undefined
null.toString() // Uncaught TypeError: // Cannot read property 'toString' of null null.valueOf() // Uncaught TypeError: // Cannot read property 'valueOf' of null null.length // Uncaught TypeError: // Cannot read property 'length' of null undefined.toString() // Uncaught TypeError: // Cannot read property 'toString' of undefined undefined.valueOf() // Uncaught TypeError: // Cannot read property 'valueOf' of undefined undefined.length // Uncaught TypeError: // Cannot read property 'length' of undefined
In practice
Advice 1
🛠 Very rarely is it necessary to call the methods of an object or primitive without using a variable (as in the examples from the article). This negatively impacts the readability of the code. It is better to always use variables to store values. This way, you can safely call methods of both the object and the primitive, and JavaScript will figure out what to do to produce the desired result.