quiz/js: prototypical inheritance and arrow function (#441)

This commit is contained in:
Vikas yadav 2024-06-05 06:02:08 +05:30 committed by GitHub
parent 0c929adf73
commit b09b96192f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 253 additions and 1 deletions

View File

@ -2,7 +2,9 @@
title: Explain how prototypal inheritance works
---
This is an extremely common JavaScript interview question. All JavaScript objects have a `__proto__` property with the exception of objects created with `Object.create(null)`, that is a reference to another object, which is called the object's "prototype". When a property is accessed on an object and if the property is not found on that object, the JavaScript engine looks at the object's `__proto__`, and the `__proto__`'s `__proto__` and so on, until it finds the property defined on one of the `__proto__`s or until it reaches the end of the prototype chain. This behavior simulates classical inheritance, but it is really more of [delegation than inheritance](https://davidwalsh.name/javascript-objects).
## TL;DR
Prototypical inheritance in JavaScript is a way for objects to inherit properties and methods from other objects. Every JavaScript object has a special hidden property called `[[Prototype]]` (commonly accessed via `__proto__` or using `Object.getPrototypeOf()`) that is a reference to another object, which is called the object's "prototype". When a property is accessed on an object and if the property is not found on that object, the JavaScript engine looks at the object's `__proto__`, and the `__proto__`'s `__proto__` and so on, until it finds the property defined on one of the `__proto__`s or until it reaches the end of the prototype chain. This behavior simulates classical inheritance, but it is really more of [delegation than inheritance](https://davidwalsh.name/javascript-objects).
## Example of Prototypal Inheritance
@ -44,6 +46,132 @@ Things to note are:
- `.makeSound` is not defined on `Dog`, so the engine goes up the prototype chain and finds `.makeSound` off the inherited `Animal`.
- Using `Object.create` to build the inheritance chain is no longer recommended. Use `Object.setPrototypeOf` instead.
---
## Prototypical Inheritance in Javascript
Prototypical inheritance is a feature in JavaScript used to create objects that inherit properties and methods from other objects. Instead of a class-based inheritance model, JavaScript uses a prototype-based model, where objects can directly inherit from other objects.
### Key Concepts
1. **Prototypes** : Every object in Javascript has a prototype, which is another object. When you create an object using an object literal or a constructor function, the new object is linked to the prototype of its constructor function or the `Object.prototype` if no prototype is specified. This is commonly referenced using `__proto__` or `[[Prototype]]`. You can also get the prototype by using inbuilt method `Object.getPrototypeOf()` and you can set the prototype of an object via `Object.setPrototypeOf()`.
```js
// Define a constructor function
function Person(name, age) {
this.name = name;
this.age = age;
}
// Add a method to the prototype
Person.prototype.sayHello = function () {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
// Create a new object using the constructor function
let john = new Person('John', 30);
// The new object has access to the methods defined on the prototype
john.sayHello(); // "Hello, my name is John and I am 30 years old."
// The prototype of the new object is the prototype of the constructor function
console.log(john.__proto__ === Person.prototype); // true
// You can also get the prototype using Object.getPrototypeOf()
console.log(Object.getPrototypeOf(john) === Person.prototype); // true
// You can set the prototype of an object using Object.setPrototypeOf()
let newProto = {
sayGoodbye: function () {
console.log(`Goodbye, my name is ${this.name}`);
},
};
Object.setPrototypeOf(john, newProto);
// Now john has access to the methods defined on the new prototype
john.sayGoodbye(); // "Goodbye, my name is John"
// But no longer has access to the methods defined on the old prototype
console.log(john.sayHello); // undefined
```
2. **Prototype Chain**: When a property or method is accessed on an object, JavaScript first looks for it on the object itself. If it doesn't find it there, it looks at the object's prototype, and then the prototype's prototype, and so on, until it either finds the property or reaches the end of the chain (i.e., null).
3. **Constructor Functions**: JavaScript provides constructor functions to create objects. When a function is used as a constructor with the new keyword, the new objects prototype ([[Prototype]]) is set to the constructors prototype property.
```js
// Define a constructor function
function Animal(name) {
this.name = name;
}
// Add a method to the prototype
Animal.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
// Define a new constructor function
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
// Set the prototype of Dog to be a new instance of Animal
Dog.prototype = Object.create(Animal.prototype);
// Add a method to the Dog prototype
Dog.prototype.bark = function () {
console.log('Woof!');
};
// Create a new object using the Dog constructor function
let fido = new Dog('Fido', 'Labrador');
// The new object has access to the methods defined on its own prototype and the Animal prototype
fido.bark(); // "Woof!"
fido.sayName(); // "My name is Fido"
// If we try to access a method that doesn't exist on the Dog prototype or the Animal prototype, JavaScript will return undefined
console.log(fido.fly); // undefined
```
4. **Object.create()**: This method creates a new object with the specified prototype object and properties. It's a straightforward way to set up prototypical inheritance. If you create a object via `Object.create(null)` it will not inherit any properties from `Object.prototype`. This means the object will not have any built-in properties or methods like `toString()`, `hasOwnProperty()`,
```js
// Define a prototype object
let proto = {
greet: function () {
console.log(`Hello, my name is ${this.name}`);
},
};
// Use `Object.create()` to create a new object with the specified prototype
let person = Object.create(proto);
person.name = 'John';
// The new object has access to the methods defined on the prototype
person.greet(); // "Hello, my name is John"
// Check if the object has a property
console.log(person.hasOwnProperty('name')); // true
// Create an object that does not inherit from Object.prototype
let animal = Object.create(null);
animal.name = 'Rocky';
// The new object does not have any built-in properties or methods
console.log(animal.toString); // undefined
console.log(animal.hasOwnProperty); // undefined
// But you can still add and access custom properties
animal.describe = function () {
console.log(`Name of the animal is ${this.name}`);
};
animal.describe(); // "Name of the animal is Rocky"
```
## Resources
- [Inheritance and the prototype chain | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

View File

@ -2,6 +2,8 @@
title: What advantage is there for using the arrow syntax for a method in a constructor?
---
## TL;DR
The main advantage of using an arrow function as a method inside a constructor is that the value of `this` gets set at the time of the function creation and can't change after that. So, when the constructor is used to create a new object, `this` will always refer to that object. For example, let's say we have a `Person` constructor that takes a first name as an argument has two methods to `console.log` that name, one as a regular function and one as an arrow function:
```js
@ -40,4 +42,126 @@ sayNameFromWindow2(); // John
The main takeaway here is that `this` can be changed for a normal function, but the context always stays the same for an arrow function. So even if you are passing around your arrow function to different parts of your application, you wouldn't have to worry about the context changing.
---
## Arrow functions
Arrow functions are introduced in ES6 and it provides a concise way to write functions in Javascript. One of the key features of arrow function is that it lexically bind the `this` value, which means that it takes the `this` value from containing scope.
### Syntax
Arrow functions use the `=>` syntax instead of the function keyword. The basic syntax is:
```js
let myFunction = (arg1, arg2, ...argN) => {
// function body
};
```
If the function body has only one expression, you can omit the curly braces and the return keyword:
```js
let myFunction = (arg1, arg2, ...argN) => expression;
```
### Examples
```js
// Arrow function with parameters
let multiply = (x, y) => x * y;
// Arrow function with no parameters
let sayHello = () => 'Hello, World!';
// Arrow function with a single parameter (parentheses can be omitted)
let square = (x) => x * x;
```
### Advantages
- Arrow functions provide a more concise syntax, especially for short functions.
- They have an implicit return for single-line functions.
- Arrow functions lexically bind the `this` value, inheriting it from the enclosing scope.
### Limitations
- Arrow functions cannot be used as constructors and will throw an error when used with the `new` keyword.
```js
const Foo = () => {};
const foo = new Foo(); // TypeError: Foo is not a constructor
```
- They do not have their own `this`,` arguments`, `super`. Since arrow functions do not have their own this, they are not suitable for defining methods in an object. Traditional function expressions or function declarations should be used instead.
```js
const obj = {
value: 42,
getValue: () => this.value, // `this` does not refer to `obj`
};
console.log(obj.getValue()); // undefined
```
## What makes arrow function good to be used for a method in constructor
One of the most notable features of arrow functions is their behavior with `this`. Unlike regular functions, arrow functions do not have their own `this`. Instead, they inherit `this` from the parent scope at the time they are defined. This makes arrow functions particularly useful for scenarios like event handlers, callbacks, and methods in classes.
### Arrow Function inside function constructor
```js
const Person = function (firstName) {
this.firstName = firstName;
this.sayName1 = function () {
console.log(this.firstName);
};
this.sayName2 = () => {
console.log(this.firstName);
};
};
const john = new Person('John');
const dave = new Person('Dave');
john.sayName1(); // John
john.sayName2(); // John
// The regular function can have its 'this' value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because "this" is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because 'this' is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because 'this' is now the dave object)
john.sayName2.bind(dave)(); // John
var sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because 'this' is now the window object)
var sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John
```
### Arrow Function in an Event Handler
```js
const button = document.getElementById('myButton');
button.addEventListener('click', function () {
console.log(this); // Output: Button
console.log(this === button); // Output: true
});
button.addEventListener('click', () => {
console.log(this); // Output: Window
console.log(this === window); // Output: true
});
```
This can be particularly helpful in React class components. If you define a class method for something such as a click handler using a normal function, and then you pass that click handler down into a child component as a prop, you will need to also bind `this` in the constructor of the parent component. If you instead use an arrow function, there is no need to also bind "this", as the method will automatically get its "this" value from its enclosing lexical context. (See this article for an excellent demonstration and sample code: https://medium.com/@machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb)
## Resources
- [Arrow function expressions - MDN ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
- [How to Use JavaScript Arrow Functions Explained in Detail](https://www.freecodecamp.org/news/javascript-arrow-functions-in-depth/)