Everything is inherited from the Object Prototype in Javascript.
In this blog, you ll learn
- Why typeof class is `function`
- Why can we use methods of objects in array, string, and function?
- Unraveling Prototypal Inheritance:
- Embracing the Object Hierarchy:
Introduction:
As a language, JavaScript often presents developers with intriguing quirks and behaviors. One such phenomenon is the result of using the typeof
operator on both class and function declarations, which returns 'function'
. This blog will explore the reasons behind this seemingly counterintuitive behavior, shedding light on JavaScript's inner workings of a prototype-based inheritance system.
The Advent of Classes in JavaScript
With the advent of ECMAScript 6 (ES6), JavaScript introduced classes, providing developers with a more structured and familiar syntax for object-oriented programming. Despite their syntax resembling classical inheritance, classes in JavaScript are primarily syntactic sugar over the prototype-based system that JavaScript has always had.
Have you ever wondered how a constructor is called automatically when we create an object of class? Don't worry you will get your answer at the end of this blog.
Under the hood, the class
keyword in JavaScript works by leveraging JavaScript's existing prototype-based inheritance system while providing a more familiar and convenient syntax for defining object-oriented structures. When you define a class using the class
keyword, JavaScript essentially performs several steps behind the scenes to create a constructor function and set up the prototype chain. Here's a simplified overview of how it works:
Class Declaration: When you declare a class using the class
keyword, JavaScript creates a new object that acts as a blueprint for instances of that class. This object contains methods and properties defined within the class definition.
class Student {
constructor(name, age) {
this.name = name;
this.age = age;
}
getAge() {
return this.age;
}
}
How does it look under the hood?
function Student(name , age) {
this.name = name;
this.age = age;
}
Student.prototype.getAge = function() {
return this.age;
};
const rehmat = new Student('Rehmat', 20);
console.log(rehmat.getAge()); // 20
So now you got my point? there are no real classes in JavaScript. Everything is a function, which is why when you use typeof with class, the return type is function.
Now let's move one step forward and see why we can use methods of objects in array, string, and also in function.
JavaScript, with its versatility and dynamic nature, often leads to intriguing discoveries. One such concept is the idea that everything in JavaScript is an object, whether it’s a primitive value like a string or a complex structure like a function or an array. Lets take an example.
Here you can see a function named Student.
function Student(name, age) {
this.name = name;
this.age = age;
}
console.log(typeof Student); // Output: 'function'
console.log(Student.length); // Output: 2(number of parameters)
console.log(Student.name); // Output: 'Student'
Despite being declared as a function, Student
exhibits object-like properties. The typeof
operator returns 'function'
, but you can also access properties like length
and name
. This behavior is not unique to Student
—all functions in JavaScript possess these properties, thanks to JavaScript's flexible and dynamic nature.
Extending Functions with Properties
The magic doesn’t stop there. You can dynamically add properties and methods to functions, further blurring the distinction between functions and traditional objects:
function Student(name , age) {
this.name = name;
this.age = age;
}
Student.rehmat = function() {
return 'Rehmat';
};
console.log(Student.rehmat()); // Rehmat
Here, we’ve added a property rehmat
to the Student
function. Despite being declared as a function, Student
now behaves like an object with an additional property. This showcases the dynamic nature of JavaScript functions and their ability to evolve beyond their initial definition.
At the heart of JavaScript lies the Object
prototype, from which all other objects inherit. Whether it's functions, arrays, strings, or custom objects, everything in JavaScript ultimately traces its lineage back to Object
. This unifying principle underscores JavaScript's simplicity and elegance, empowering developers to work with a consistent set of principles and patterns.
Object
prototypeThis is due to JavaScript's prototype-based inheritance model, which forms the foundation of its object-oriented programming paradigm.
Strings as Objects:
Although str
appears to be a simple string, it possesses object-like properties and behaviors. Let's delve deeper into its object-like characteristics:
const str = 'rehmat';
Prototype Inheritance:
console.log(str.__proto__ === String.prototype); // true
console.log(str.__proto__.__proto__ === Object.prototype); // true
The __proto__
property of str
points to the String
prototype, which, in turn, inherits from the Object
prototype. This establishes a prototypal chain that links the string str
to the Object
prototype, imbuing it with object-like features.
Object Methods on Strings:
console.log(str.hasOwnProperty('length')); // true
console.log(str.hasOwnProperty('rehmat')); // false
Despite being a string, str
can utilize object methods like hasOwnProperty
. This behavior is a result of JavaScript's prototypal inheritance model, which allows objects—including strings—to inherit properties and methods from their prototype chain.
Indeed, the length
property, present in various data types such as functions, strings, arrays, and even objects, stems from JavaScript's prototypal inheritance model. As you correctly pointed out, these data types inherit this property from the Object
prototype, which serves as the foundation of their inheritance chain.
Inheritance of Length Property:
Let’s examine how the length
property is inherited across different data types:
- Functions
- Array
- Objets
- String
function myFunction(a, b) {}
console.log(myFunction.length); // Output: 2
// array
const myArray = [1, 2, 3];
console.log(myArray.length); // Output: 3
// objects
const myObject = { a: 1, b: 2, c: 3 };
console.log(Object.keys(myObject).length); // Output: 3
//string
const myString = 'Hello';
console.log(myString.length); // Output: 5
Understanding this inheritance mechanism underscores the elegance and simplicity of JavaScript’s object-oriented model, empowering developers to write expressive and concise code while leveraging the language’s versatile features.