Javascript Challenge 1

# Javascript Challenges
## Challenge 1 

- Try to guess what the below code prints.
- Fix the code

```
let person = {
  name: 'John Doe',
  getName: function() {
      console.log(this.name);
  }
};

setTimeout(person.getName, 1000);
```
Lets do some analysis
### When Method is in an Object: 
- The method `getName` is initially defined as part of the `person` object. 
- When you call `person.getName()`, the `this` keyword refers to the `person` object. So `this.name` would correctly return 'John Doe'.

### The Issue with `setTimeout`
- However, when a function is passed as a callback (like `person.getName` in this case), it loses its context (i.e., the reference to the person object). 
- Instead, the value of `this` inside `getName` changes to the global object (window in browsers, or global in Node.js).
- In non-strict mode, the global object (`window `in browsers) doesn't have a name property, so `this.name` becomes `undefined`.

### How `this` changes in `setTimeout`:
- When `setTimeout` calls `person.getName`, it is invoked as a regular function, not as a method on the `person` object.
- In this case, `this` inside `getName` no longer refers to the `person` object, but instead refers to the global object (`window`), which does not have a name property.
- Therefore, console.log(this.name) outputs `undefined`.

## Solutions
- Solution 1: Use .bind() to explicitly set the context of this:

    ```
    setTimeout(person.getName.bind(person), 1000);
    ```

- Solution 2: Use an Arrow Function (which doesn't have its own this):

    ```
    setTimeout(() => person.getName(), 1000);
    ```

    Arrow functions do not have their own `this`, so they inherit the this from the surrounding lexical context.
    In this case, the surrounding context is the object `person`, so this inside the arrow function will correctly refer to the person object.

- Solution 3: Store this in a variable (for older browsers or environments that don’t support .bind() or arrow functions)

    ```
    let self = person;
    setTimeout(function() {
        self.getName();
    }, 1000);
    ```
- Solution 4: Simply using anonymous function and person object
    ```
    setTimeout(function() {
        person.getName();
    }, 1000);
    ```

## Challenge 2
Consider the following function declaration.
```
function MyClass() {
  this.name = 'John Doe';
  
  setTimeout(function() {
    console.log(this.name); 
  }, 1000);
}

```
- Try to guess what the below code prints.
- Please fix the code

## Solutions
If we observe the below logging statement, 

`console.log(this.name);`

here `this` will refer to the global object, not MyClass

### Solution 1 
 If you're using a regular function (not an arrow function), and you want to preserve the value of `this`, using a variable like `self` or `that` to store the reference to the context of this (such as the object that owns the method) makes sense.
 Below code shows that approach.
```
function MyClass() {
  this.name = 'John Doe';
  let self = this;  // Preserve `this` in `self`
  
  setTimeout(function() {
    console.log(self.name);  // `self` still refers to the MyClass instance
  }, 1000);
}

```

### Solution 2
- Using Arrow functions!

```
function MyClass() {
  this.name = 'John Doe';
  
  setTimeout(() => {
    console.log(this.name);  // `this` now refers to the MyClass instance
  }, 1000);
}

const myInstance = new MyClass(); 
```

### Arrow Function Behavior: 

- The arrow function (() => {}) inside setTimeout does not have its own `this`.
- Instead, it inherits the this value from its surrounding lexical context. 
- In this case, the lexical context is the MyClass constructor, where this refers to the instance of MyClass.

Comments

Popular posts from this blog

Java8 Stream Examples

Java8 Introduction