Javascript class properties, eventlistener and object properties. Constant scope outside constructor not working

203 Views Asked by At

I am trying to create an object that each property is a class property.

This means I have a class named Ship which has 3 properties: type, length, orientation. I am trying to create an object named shipObj that all its properties are getting values from these class properties. Apart from the id property (which is the id of an event target).

Look at the code below.

class Ship{

  constructor(type, length){
    this.type = type
    this.length = length
    this.orientation = 'horizontal'
    const self = this
  }

  // Deploying ships by dragging them into the grid
  deployShip = () => {

    self.addEventListener('dragstart', function(e) {

      // Ship object for json
      let shipObj = {
        id: e.target.id,
        type: self.type,
        length: self.length,
        orientation: self.orientation
      }

      e.dataTransfer.setData( 'text/plain', JSON.stringify(shipObj) );
    });

  }

}

For example, when I create this Ship Object let carrier = new Ship("Carrier", 5),

I want shipObj to be like this {id: 'carrier-chris', type: 'Carrier', length: '5', orientation: 'horizontal'}.

How can I do that?

The result I currently get is {id: 'carrier-chris', type: 'undefined', length: '0', orientation: 'undefined'}. As you can see I am creating a constant named self at the constructor but for some reason its scope is limited only inside the constructor.

1

There are 1 best solutions below

2
On BEST ANSWER

You'll need to put the const self = this declaration inside the deployShip method, so that it is in scope where it is used:

class Ship {
  …

  // Deploying ships by dragging them into the grid
  deploy() {
    const self = this;
//  ^^^^^^^^^^^^^^^^^^
    window.addEventListener('dragstart', function(e) {
//  ^^^^^^ ???

      // Ship object for json
      let shipObj = {
        id: e.target.id,
        type: self.type,
        length: self.length,
        orientation: self.orientation
      }
      e.dataTransfer.setData( 'text/plain', JSON.stringify(shipObj) );
    });
  }
}

Alternatively, don't use self = this but just an arrow function:

class Ship {
  …

  // Deploying ships by dragging them into the grid
  deploy() {
    window.addEventListener('dragstart', (e) => {
//                                       ^^^^^^^^
      // Ship object for json
      let shipObj = {
        id: e.target.id,
        type: this.type,
//            ^^^^
        length: this.length,
//              ^^^^
        orientation: this.orientation
//                   ^^^^
      }
      e.dataTransfer.setData('text/plain', JSON.stringify(shipObj) );
    });
  }
}

Here, this inside the event handler will still refer to the same this value that the deploy() method was called, i.e. the Ship instance if you did call ship.deploy();.