1

In the following code how do I get the this keyword to bind to Square?

Square.prototype.is = {
  king: function () { this.piece === "K" }
  queen: function () { this.piece === "Q" }
  ...
};

I know I can later on use call/apply but the whole point was to get from

this.isKing()

to

this.is.king()

making it more readable (also grouping the methods together)

this.is.king.apply(this)

seems like a step backwards.

David
  • 138
  • 1
  • 9
  • 1
    What does `this` refer to? `this` refering to a Chess instance or `this` referring to some other object? – kemicofa ghost Nov 24 '18 at 13:04
  • I edited my post, the class in questions is named `Square` not `Chess`. All the `this` keywords refer to a `Square` instance – David Nov 24 '18 at 13:15
  • What if you return`this` on both king and queen fns – enapupe Nov 24 '18 at 13:20
  • Sorry, I don't quite get what you mean. You mean the methods in the first code block? The problem is going from Square.prototype.isKing = function() { return this.piece === "K"} to Square.prototype.is = { king: function() { return this.piece === "K" } } changes what the `this` key refers to. In the first example it refers to a Square instance, in the second it refers to the Square.prototype.is object. I might have answered your first question wrong, sorry for the confussion – David Nov 24 '18 at 13:29

2 Answers2

1

I would suggest using ES6 arrow functions. This is a syntax that is supported by all major browsers now. Using arrow functions allows us to leverage the outer scope's this.

An example using Class:

class Square {
  constructor(){
    this.piece = null;
    this.is = {
      king: () => this.piece === "K",
      queen: () => this.piece === "Q"
    }
  }
};

const square = new Square();
square.piece = 'K';

console.log(square.is.king());
console.log(square.is.queen());

If you're determined to use ES5 syntax:

var Square = function Square() {
  var _this = this;
  this.piece = null;
  this.is = {
    king: function() { return _this.piece === "K" },
    queen: function() { return _this.piece === "Q" }
  };
};


var square = new Square();
square.piece = 'K';

console.log(square.is.king());
console.log(square.is.queen());

Finally, per @Bergi's comment, here's one more approach, using arrow functions and objects, without any Classes.

const Square = function Square() {  
  this.piece = null;
  this.is = {
    king: () => this.piece === "K",
    queen: () => this.piece === "Q"
  };
};


const square = new Square();
square.piece = 'K';

console.log(square.is.king());
console.log(square.is.queen());
Matt Morgan
  • 4,900
  • 4
  • 21
  • 30
  • I have a lot of methods. My `class Square` block would have a few hundred lines of code. Do you still recommend doing this? Is combining the .prototype way of defining methods and the class way an option? – David Nov 24 '18 at 13:37
  • Of the two approaches, it seems like the ES6 class-based approach is the less verbose, although they are very similar in length. – Matt Morgan Nov 24 '18 at 14:09
  • This doesn't need `class`es at all, the main feature of your approach are arrow functions that are created in the scope of the constructor. – Bergi Nov 24 '18 at 14:31
  • @Bergi true enough. I've added one more simplified approach. Also cleaned up the ES5 example... – Matt Morgan Nov 24 '18 at 14:34
  • I just wanted you to edit the first sentence from "*I would suggest using ES6 classes.*" to "*I would suggest using ES6 arrow functions.*" :-) – Bergi Nov 24 '18 at 14:39
  • Done, with some additional edits. Thanks for the feedback :) – Matt Morgan Nov 24 '18 at 14:45
1

I know this does not answer directly to your question, but the is functions that are commonly found in third party libraries usually have the following signature: is(type).

In this fashion, you could write:

square.prototype.is = function(type) {
  switch (String(type).toLowerCase()) {
    case "king": return this.piece === "K";
    case "queen": return this.piece === "Q";
    default: return false;
  }
}

Assuming type would be a String. But it can an Number defined in an Object to act as a Enum.

I hope you won't consider this off-topic as it can be a solution to consider alternative ways :)

Zim
  • 1,457
  • 1
  • 10
  • 21