19 KiB
Agenda
Topics to cover in Javascript Oops
- This keyword
- Constructor functions
- Classes & Classical Inheritance
- Prototype & Prototypal Inheritance
- Call ,Apply & Bind Methods
- Memory of objects (Reference Datatypes)
We will try to cover most of these topics in today's sessions and the remaining in the next.
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
This Keyword
Certainly! When covering Object-Oriented Programming (OOP) in JavaScript, the this
keyword is a crucial concept to understand. Here's a breakdown of topics you can cover regarding the this
keyword in JavaScript and its relevance to OOP:
-
Introduction to
this
keyword:- Explain that
this
is a special keyword in JavaScript that refers to the current execution context or the current object. - Mention that its value depends on how a function is called, rather than where it is defined.
- Explain that
-
Global Context:
- Describe that in the global context (outside of any function),
this
refers to the global object (e.g.,window
in browsers,global
in Node.js).
- Describe that in the global context (outside of any function),
-
Function Context:
- Explain that within a function, the value of
this
can change based on how the function is invoked. - Discuss function invocation methods:
- Regular function invocation:
this
usually refers to the global object (in non-strict mode) orundefined
(in strict mode). - Method invocation:
this
refers to the object that the method is called on. - Constructor invocation:
this
refers to the instance being created by the constructor function. call()
andapply()
methods: Explicitly setthis
for a function call.- Arrow functions:
this
retains the value of the enclosing lexical context.
- Regular function invocation:
- Explain that within a function, the value of
-
Object-Oriented Programming (OOP) and
this
:- Explain how
this
is used in the context of OOP to refer to the instance of an object. - Describe how methods within an object can access other properties and methods using
this
.
- Explain how
-
Common
this
Pitfalls:- Describe issues that developers often face with
this
:- Losing
this
context in nested functions. - Using
this
in callbacks without proper binding. - Caching
this
in a variable to ensure proper reference in nested scopes.
- Losing
- Describe issues that developers often face with
-
Solving
this
Issues:- Introduce solutions to common
this
problems:- Using
.bind()
,.call()
, or.apply()
to explicitly setthis
. - Storing a reference to the outer
this
in a variable to use within nested functions. - Using arrow functions to preserve the lexical scope's
this
.
- Using
- Introduce solutions to common
-
Examples and Demonstrations:
- Provide code examples for each type of function invocation and how
this
behaves in each case. - Show scenarios where
this
is used within object methods to access object properties.
- Provide code examples for each type of function invocation and how
-
Best Practices:
- Emphasize the importance of understanding the context in which
this
is used. - Encourage using arrow functions in methods when you want to retain the outer scope's
this
. - Suggest using modern ES6 features like classes to manage
this
more effectively.
- Emphasize the importance of understanding the context in which
-
Browser vs. Node.js:
- Mention the differences in the global object (
window
vs.global
) and how they affectthis
behavior.
- Mention the differences in the global object (
this
keyword in Node.js in non-strict mode
Certainly, let's break down the behavior of the this
keyword in Node.js in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: fn
is a function defined globally, and obj
is an object containing a method fn
.
// Scenario 1: Console.log(this)
console.log("Scenario 1:");
console.log(this); // Output: {}
// Scenario 2: Console.log(this) -> fn = global object
console.log("Scenario 2:");
function fnGlobal() {
console.log(this === global); // true
}
fnGlobal();
// Scenario 3: this -> obj -> fn = object itself
console.log("Scenario 3:");
var obj = {
fn: function () {
console.log(this === obj); // true
}
};
obj.fn();
// Scenario 4: this -> obj -> fn -> fn = global object
console.log("Scenario 4:");
var obj2 = {
fn: function () {
console.log(this === obj2); // true
var nestedFn = function () {
console.log(this === global); // true
};
nestedFn();
}
};
obj2.fn();
Now, let's summarize these scenarios in a tabular form:
Scenario | Code | Output | Explanation |
---|---|---|---|
1 | console.log(this); |
{} |
In global context, this refers to the global object. |
2 | function fnGlobal() {...} fnGlobal(); |
true (inside the function) |
In a regular function, this refers to the global object. |
3 | obj.fn = function() {...} obj.fn(); |
true (inside the method) |
Inside an object method, this refers to the object itself. |
4 | obj2.fn = function() {...} obj2.fn(); |
true (inside the method)true (inside nested function) |
Inside a nested function, this reverts to the global object. |
In scenarios 3 and 4, this
refers to the object containing the method when that method is directly invoked. However, when a nested function is defined within the method and invoked within it, this
inside the nested function refers to the global object (global
in Node.js).
Understanding these behaviors helps in writing clean and predictable code, especially when dealing with methods and nested functions within objects.
this
keyword in Browser in non-strict mode
Certainly, let's break down the behavior of the this
keyword in Browser in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: fn
is a function defined globally, and obj
is an object containing a method fn
.
Sure, let's break down each scenario and then summarize them in a tabular form.
Scenario 1: console.log(this)
console.log(this); // Window Object
In this scenario, if you directly execute console.log(this)
in the global context of a web browser (not within any function or object), the output will be the Window
object. This is because this
refers to the global object, which is the Window
object in a browser environment.
Scenario 2: console.log(this)
inside a function
function exampleFunction() {
console.log(this);
}
exampleFunction(); // Window Object
In this case, when you call exampleFunction()
, it's being invoked as a regular function. The this
inside the function still refers to the global object (Window
in the browser).
Scenario 3: this
inside an object method
var obj = {
prop: 'I am a property',
method: function() {
console.log(this.prop);
}
};
obj.method(); // "I am a property"
In this scenario, obj
is an object containing a method named method
. When you call obj.method()
, the this
inside the method
refers to the obj
itself. Therefore, this.prop
accesses the prop
property of the obj
object.
Scenario 4: this
inside nested functions
var obj = {
prop: 'I am a property',
method: function() {
var nestedFunction = function() {
console.log(this.prop);
};
nestedFunction();
}
};
obj.method(); // undefined
Here, within the nestedFunction
, this
refers to the global object (Window
in the browser). This is because the function nestedFunction
is not a method of obj
. As a result, this.prop
will be undefined
since the global object doesn't have a prop
property.
Now, let's summarize these scenarios in a tabular form:
Scenario | this Value |
Explanation |
---|---|---|
console.log(this) |
Window Object | Global context, this refers to the global object (Window in browser). |
console.log(this) |
Window Object | Inside a regular function, this still refers to the global object. |
this in object method |
obj (object itself) |
Inside a method, this refers to the object on which the method is invoked. |
this in nested function |
Window Object | Inside a nested function, this refers to the global object. |
Understanding these scenarios is important for grasping how this
behaves in different contexts within a browser environment.
this
keyword in Node.js in strict mode
Certainly, let's break down the behavior of the this
keyword in Node.js in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: fn
is a function defined globally, and obj
is an object containing a method fn
. Here's what each scenario seems to be referring to:
-
console.log(this)
(Scenario 1):"use strict"; console.log(this); // Outputs an empty object ({})
In strict mode, when you log
this
in the global context, it will be an empty object{}
. This is because strict mode prevents the default binding ofthis
to the global object. -
console.log(this)
with Undefined Function (Scenario 2):"use strict"; function myFunction() { console.log(this); } myFunction(); // Outputs undefined
In strict mode, when you call a function without specifying its context (
this
), it's set toundefined
. This is different from non-strict mode, where it would point to the global object. -
this
Inside an Object Method (Scenario 3):"use strict"; var obj = { prop: "I'm a property", method: function() { console.log(this.prop); } }; obj.method(); // Outputs "I'm a property"
When a method is invoked on an object,
this
within the method refers to the object itself. So,this.prop
accesses theprop
property of theobj
object. -
this
Inside Nested Object Methods (Scenario 4):"use strict"; var outerObj = { innerObj: { method: function() { console.log(this); } } }; outerObj.innerObj.method(); // Outputs the inner object
Inside nested object methods,
this
refers to the closest containing object. In this case, it points toinnerObj
when themethod
is invoked.
Now, let's summarize these scenarios in tabular form:
Scenario | Example Code | this Value |
Explanation |
---|---|---|---|
1 | console.log(this); |
{} |
In strict mode, this is an empty object in the global context. |
2 | myFunction(); |
undefined |
Calling a function without context results in undefined . |
3 | obj.method(); |
obj object reference |
this in an object method points to the object itself. |
4 | outerObj.innerObj.method(); |
innerObj object reference |
In nested methods, this refers to the closest containing object. |
Understanding these scenarios and how this
behaves in different contexts is crucial for writing reliable and maintainable code.
this
keyword in Browser in strict mode
Certainly, let's break down the behavior of the this
keyword in Browser in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: fn
is a function defined globally, and obj
is an object containing a method fn
. Assuming you have the following setup in a browser environment:
"use strict";
// Scenario 2
console.log("Scenario 2:");
console.log(this); // Output: undefined
// Scenario 3
var obj = {
fn: function () {
console.log("Scenario 3:");
console.log(this); // Output: obj
},
};
// Scenario 4
var fn = obj.fn;
// Scenario 1
console.log("Scenario 1:");
console.log(this); // Output: window
// Scenario 4 (contd.)
console.log("Scenario 4:");
fn(); // Output: undefined
Now, let's summarize these scenarios in a tabular form:
Scenario | Code | this Value |
Explanation |
---|---|---|---|
1 | console.log(this); |
window object |
In the global context, this refers to the global object (window in browsers). |
2 | "use strict"; console.log(this); |
undefined |
In strict mode, this in the global context is undefined . |
3 | obj.fn(); |
obj object |
When calling a method (fn ) of an object (obj ), this refers to the object itself (obj ). |
4 | var fn = obj.fn; fn(); |
undefined |
When a method (fn ) is assigned to a variable (fn ) and called, this is undefined . |
In summary:
- In the global context, outside of any function,
this
refers to the global object (window
in browsers). - In strict mode, in the global context,
this
isundefined
. - When a function is a method of an object,
this
within the function refers to the object itself. - If a method is assigned to a variable and then invoked,
this
inside the method will beundefined
.
Remember, the behavior of this
can be a bit tricky, especially when dealing with nested functions, callbacks, and different contexts. Understanding these scenarios helps you write more predictable and maintainable code in JavaScript.
Constructor Functions
In JavaScript, constructor functions are used to create and initialize objects. They serve as templates for creating objects with similar properties and methods. Constructor functions are typically written with an initial capital letter to distinguish them from regular functions.
A constructor function defines the structure of an object by setting its properties and methods using the this
keyword. When you create an object using a constructor function with the new
keyword, it creates a new instance of that object type and binds the instance to the this
keyword within the constructor function.
Car Company Example:
Imagine you're building a car manufacturing company. Each car will have properties like the make, model, year, and color. You can create a constructor function called Car
to represent a car object.
Coding Example:
Here's how you can implement the car company example using a constructor function:
// Constructor function for Car
function Car(make, model, year, color) {
this.make = make;
this.model = model;
this.year = year;
this.color = color;
this.start = function() {
console.log(`Starting the ${this.make} ${this.model}`);
};
}
// Creating car instances
const car1 = new Car("Toyota", "Camry", 2022, "Blue");
const car2 = new Car("Ford", "Mustang", 2023, "Red");
// Using the car instances
console.log(car1); // Car { make: 'Toyota', model: 'Camry', year: 2022, color: 'Blue' }
console.log(car2); // Car { make: 'Ford', model: 'Mustang', year: 2023, color: 'Red' }
car1.start(); // Starting the Toyota Camry
car2.start(); // Starting the Ford Mustang
In this example:
- The
Car
constructor function defines the properties (make
,model
,year
,color
) and thestart
method for a car object. - Instances of cars (
car1
andcar2
) are created using the constructor function. - The
start
method is accessed and invoked on each car instance.
By using constructor functions, you can create multiple car instances with the same structure but different property values. This follows the fundamental concept of OOP, where you create objects based on blueprints (constructor functions) that define their structure and behavior.
Constructor function with this
example
// Constructor function for Car
function Car(nameParam, colorParam, topSpeedParam) {
// Using 'this' to refer to instance-specific properties
this.name = nameParam;
this.color = colorParam;
this.topSpeed = topSpeedParam;
// Using 'this' to refer to instance-specific method
this.drive = function() {
console.log(`I am driving ${this.name}`);
};
}
// Creating car instances using 'new'
let car1 = new Car("Ferrari", "Red", '1000km/hr');
let car2 = new Car("8", 'white', '600km/hr');
// Using the car instances
car1.drive(); // Output: I am driving Ferrari
car2.drive(); // Output: I am driving 8
Explanation of this
usage:
-
In the constructor function (
Car
):- When creating a new instance using the constructor with
new
, thethis
keyword refers to the newly created instance. - Properties (
name
,color
,topSpeed
) are assigned to the instance usingthis
followed by the property name. For example,this.name
refers to thename
property of the specific instance being created. - The
drive
method is assigned to each instance withthis.drive
. Inside thedrive
method,this.name
refers to thename
property of the instance that is calling the method. This allows each instance to have its own unique behavior.
- When creating a new instance using the constructor with
-
When creating car instances:
let car1 = new Car("Ferrari", "Red", '1000km/hr');
creates an instance ofCar
namedcar1
. Within the constructor,this.name
becomes "Ferrari" forcar1
.let car2 = new Car("8", 'white', '600km/hr');
creates another instance namedcar2
. Inside the constructor,this.name
becomes "8" forcar2
.
-
Using the car instances:
- Calling the
drive
method oncar1
(car1.drive()
) prints "I am driving Ferrari". Within the method,this.name
refers to thename
property ofcar1
. - Calling the
drive
method oncar2
(car2.drive()
) prints "I am driving 8". Within the method,this.name
refers to thename
property ofcar2
.
- Calling the
The this
keyword is essential in JavaScript's OOP to distinguish properties and methods of each individual instance when using constructor functions to create objects.