iknownothing
iknownothing

Reputation: 125

Struggling to get the ES6 this binding to work

I wrote this snippet of code, trying to create an impromptu fighting game. It uses the old style function keyword, therefore when I want to use a helper function isAlive I'm forced to do a very ugly 'this' binding.

I'm trying to grasp how 'this' behaves differently with arrow functions but when I change the first line to ES6 syntax and drop the binding it always returns false.

let isAlive = () => this.health > 0;

What am I doing wrong? I'm pretty sure the syntax itself is OK.

let isAlive = function () { return this.health > 0};

let getFighter = function (color, strength) {
    return {
        color: color,
        health: 100,
        strength: typeof strength !== 'undefined' ? strength : 1,
        attack: function (what) {
            hit_points = Math.floor(Math.random() * 10 * this.strength);
            document.writeln(this.color + ' fighter attacks ' + what.color + ' trying to deal ' + hit_points + ' damage.');
            what.get_hurt(hit_points);
        },
        get_hurt: function (hit_points) {
            if ( !isAlive.bind(this)() ) {
                document.writeln(this.color + ' fighter already dead!');
                document.writeln();
                return;
            } 
            this.health = this.health - hit_points;
            document.writeln(this.color + ' received ' + hit_points + ' damage and has ' + this.health + ' HP left.');
            if ( !isAlive.bind(this)() ) {
                document.writeln(this.color + ' fighter died!');
            }
            document.writeln();
        }
    };
};

blue = getFighter('Blue', 3);
red = getFighter('Red');


console.log(red);
console.log(blue);

while (isAlive.bind(blue)()) {
    red.attack(blue);
}

red.attack(blue)

Upvotes: 2

Views: 58

Answers (3)

guest271314
guest271314

Reputation: 1

You can define a parameter at isAlive function and pass the object or this to the function

let isAlive = ({health}) => health > 0; 

let getFighter = function(color, strength) {
  return {
    color: color,
    health: 100,
    strength: typeof strength !== 'undefined' ? strength : 1,
    attack: function(what) {
      hit_points = Math.floor(Math.random() * 10 * this.strength);
      document.writeln(this.color + ' fighter attacks ' + what.color 
        + ' trying to deal ' + hit_points + ' damage.');
      what.get_hurt(hit_points);
    },
    get_hurt: function(hit_points) {
      if (!isAlive(this)) {
        document.writeln(this.color + ' fighter already dead!');
        document.writeln();
        return;
      }
      this.health = this.health - hit_points;
      document.writeln(this.color + ' received ' + hit_points 
        + ' damage and has ' + this.health + ' HP left.');
      if (!isAlive(this)) {
        document.writeln(this.color + ' fighter died!');
      }
      document.writeln();
    }
  };
};

blue = getFighter('Blue', 3);
red = getFighter('Red');

console.log(red);
console.log(blue);

while (isAlive(blue)) {
  red.attack(blue);
}

red.attack(blue);

console.log(red);
console.log(blue);

Upvotes: 0

Tony Tai Nguyen
Tony Tai Nguyen

Reputation: 1633

Looking at your code example, I think we first need to understand how this works. this is will refer to your object/function that has been instantiated.

const getFighter = function(color, strength) {
  this.color = color;
  this.strength = strength && 1;

  return {
    health: 100,
    isAlive: this.health > 0,
    hit_points: () => Math.floor(Math.random() * 10 * this.strength),
    attack: (what) => {
      document.writeln(`${this.color} fighter attacks ${what.color} trying to deal ${this.hit_points} damage.`);
      what.get_hurt(this.hit_points);
      return null;
    },
    get_hurt: () => {
      if (!this.isAlive) {
        document.writeln(`${this.color} fighter already dead!`);
        return;
      }
      this.health = this.health - this.hit_points;
      document.writeln(`${this.color} received ${this.hit_points} damage and has ${this.health} HP left.`);
      if (!this.isAlive) {
        document.writeln(`${this.color} fighter died!`);
      }
    },
  };
};


const BlueFighter = new getFighter("Blue", 3);
const RedFighter = new getFighter("Red");

console.log('is Alive', BlueFighter.isAlive);
console.log('Health:', RedFighter.health);

You can see I take advantage of () => so that I can have access to this within the function. You wouldn't get this with a regular function unless you .bind(this)!

Upvotes: 1

Rosmarine Popcorn
Rosmarine Popcorn

Reputation: 10967

An arrow function does not create its own this, the this value of the enclosing execution context is used.

By defining isAlive in a different execution context, you also bind the keyword to a different this.

If you want to take advantage of arrow functions, than declare them inside your function

function foo(){
  const isAlive = () => this.health > 100;
}

In your case, if you want a helper you either declare it as a part of the object, or uses ES6 Classes and class properties will do that for you.

Upvotes: 2

Related Questions