skip to Main Content

I faced I bug I don’t totally understand so I would like to know why it happens. I understand it has something to do with the {…} spread operator but unclear what is the root of the problem.

Here is a simplified class of the one I used:

class Item {
    id:number;
    constructor(id:number) {
        this.id = id;
    }
    compareTo = (i2:Item) => {
        return this.id === i2.id;
    }
}

Now this "Item" class was inside another custom class so I copied it with spread operator but when I started to use the object I faced a weird bug when comparing the item to itself:

const selectedObj = { item: new Item(1) };
let item:Item = {...selectedObj.item};
console.log(item.id) // 1
console.log(item.compareTo(item)) //true
item.id = 123;
console.log(item.id) //123
console.log(item.compareTo(item)) //false

When I inspected this further I noticed that inside the compareTo method "this.id" did not change. Why does this happen?

2

Answers


  1. You’ve initialized the compareTo field with an arrow function; as such, it does not have its own this context. Instead this refers to whatever it refers to outside the arrow function body; for a field initializer it’s the class instance under construction. Which means that compareTo is always going to bound to the specific class instance it was constructed with, and not the object on which it was called.

    If you modify compareTo to log whether this === i2:

    compareTo = (i2: Item) => {
        console.log(this === i2)
        return this.id === i2.id;
    }
    

    you’ll see this behavior:

    let item: Item = { ...selectedObj.item };
    item.compareTo(item); // logs false
    item.compareTo(selectedObj.item); // logs true
    

    which demonstrates that item.compareTo is not bound to item, but is always bound to selectedObj.item.

    Playground link to code

    Login or Signup to reply.
  2. You need to use a class, like this.

    class Item {
        id:number;
        constructor(id:number) {
            this.id = id;
        }
        compareTo(i2:Item) {
            return this.id === i2.id;
        }
    }
    
    let selectedObj = {id: 1}
    
    let item = new Item(selectedObj.id)
    console.log(item.id) // 1
    console.log(item.compareTo(item)) //true
    item.id = 123;
    console.log(item.id) //123
    console.log(item.compareTo(item)) // true
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search