Jump to content

Getting mixed up using This scopes.


Recommended Posts

Hi all,


I am currently trying to use buttons in a game. I followed a tutorial on how to make them and they work well. The only problem is I am getting a problem with scope. I have created a board object then set alot of values using this.values. However when I made my buttons they also used this.values. I am having trouble trying to get it sorted out. Here is my code. Hopefully you can understand this better then my explanation: 

Board.prototype.setup = function() {    //Create all the buttons.    var buttonTexture = PIXI.Texture.fromImage("./button.png");    // this just makes a button and a button array.    var buttons = [];    for (var i = 0; i < this._tokenColors.length; i++) {        var button = new PIXI.Sprite(buttonTexture);        button.anchor.x = 0.0;        button.anchor.y = 0.0;        button.buttonMode = true;        button.interactive = true;        button.position.x = (viewWidth/6) * (i % 6);        button.position.y = viewHeight - 100;        button.color = this._tokenColors[i];        button.tint = button.color;                stage.addChild(button);        buttons.push(button);        //I tried getting it to use a function in the Board class.        button.mousedown = button.touchstart = function(data) {            Board.prototype.nextColor(this.color);                    };    }};//Here is the function it calls when pressedBoard.prototype.nextColor = function (color) {    document.getElementById("debug").innerHTML = color + " has been pressed";    this._nextColor = color; //This should set the BOARD'S next color    this._ready = true; //This should set the BOARD to ready}

I believe what is happening is instead of passing the values to the Board class, it is passing it to the button that calls the function instead. I just have no idea how to fix this. Any help would be greatly appreciated!



Link to comment
Share on other sites

Calling a function through the prototype is the same as calling any normal(e.g. not bound to an object) function. In other words, your assumption is correct:

-In the button.onmousedown handler, the 'this' object refers to the button.

-When the Board.prototype.nextColor() is called inside there, the 'this' object still refers to the button.


Passing values to handlers is one of the things that JavaScript is not very good at (and one of the things they try to fix in ECMAScript 6). The solution suggested by many developers is to create a second reference to the Board object, e.g:

var thisBoard = this;button.mousedown = button.touchstart = function(data) {    thisBoard.nextColor(this.color);};

I hope this helps.



Link to comment
Share on other sites

Hi Qqwy you score a point in fact, it seems to work.


Your solution is what I tried to emulate with the use of bind.


this code works too and allow not to create a new variable to reference the current board :

button.mousedown = button.touchstart = function(data) {   this.nextColor(this.color);}.bind(this);

(I've discovered bind not a long time ago, so now I try to use it when possible when I encounter a closure problem)

Link to comment
Share on other sites

Thank Qqwy! That worked perfectly. 


Xerver you said that a closure repeated created should be avoided. Are you referring to the way I call a loop to make my buttons? If so what's an alternative method? Thanks for your help!


I think what he means is using bind returns a new function each time its called, so if you're making 100 objects all with bound contexts, it's less efficient than using the 'var that = this;' approach because that will always just be a reference to the object.

Link to comment
Share on other sites

both, when you loop and create a closure each time you are creating `n` new closures that all do the same thing. Unless you *need* the iteration variable in your closure scope you can create a function normally and pass each iteration:

function onClick(e) {}for(var i = 0; i < 1000; ++i) {    something.on('click', onClick);}

That will not only be faster at run time, it will take less memory. To maintain your bound context, create the bound function once:

function MyThing() {    var boundFunc = this.onClick.bind(this);    for(var i = 0; i < 1000; ++i) {        button.mousedown = button.touchstart = boundFunc;    }}MyThing.prototype.onClick(e) {}
Link to comment
Share on other sites

Hey, Xerver,


When I tried your first method i got the error that the button has no method "on". 




When I tried the second method, I am unsure of how to get the button's colour.

Board.prototype.onClick = function(e) {    this.nextColor(e.color); //Doesn't work, also tried calling this.color but to no avail};


Link to comment
Share on other sites

It is important to understand that "this" in JavaScript is not the same as "this" in for instance, Java.  In JavaScript, the "this pointer" is contextual.  It can change due to multiple reasons, the most commonly confusing ones are in timer invoked functions and in events.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...