如何在对象函数中引用对象数据?

时间:2019-05-22 21:00:14

标签: javascript

我正在尝试制作一个简单的井字游戏来学习和练习JavaScript OOP,并且遇到了一些困难。

在触发game.turn函数时,我想引用game.handleClick的值。我知道使用this关键字引用了被调用对象的范围,在handleClick中,this引用了被点击的game-tile-x。如何引用“ handleClick”功能范围之外的对象值?

任何帮助将不胜感激!

<div id="game-board">
    <div id="game-tile-1" class="game-tile"></div>
    <!-- divs 2-8 -->
    <div id="game-tile-9" class="game-tile"></div>
</div>
function Game() {
    this.tiles = document.getElementsByClassName('game-tile'),
    this.turn = 0;

    this.init = function() {
        for (let i = 0; i < this.tiles.length; i++) {
            // reset game tiles
            this.tiles[i].innerHTML = '';

            // setup event listeners
            this.tiles[i].addEventListener('click', this.handleClick);
        }
    };
    this.handleClick = function() {
        let id = parseInt(this.id.replace('game-tile-', ''));
        console.log(id); // returns 0, 1, 2, etc.
        console.log(this.turn); // returns undefined
    };
}

let game = new Game();
game.init();

4 个答案:

答案 0 :(得分:1)

您可以使用curried函数,并使用游戏实例(this)调用外部函数,然后在内部使用它:

 this.tiles[i].addEventListener('click', this.handleClick(this));

 //...

this.handleClick = function(game) {
 return function() {
    let id = parseInt(this.id.replace('game-tile-', ''));
    console.log(id); // returns 0, 1, 2, etc.
    console.log(game.turn); 
 };
};

答案 1 :(得分:1)

JavaScript的this值是在调用时及其调用方式确定的。当您单击图块时,浏览器会通过调用handleClick做出反应。 this值通常是单击的元素。 this.turnundefined,因为您的元素没有属性turn

您要做的是将this的值存储在范围内的单独变量中。这样,您无需使用关键字this就可以引用this

function Game() {
  // The value of "this" in a constructor is the instance of the constructor.
  // We store a reference of "this" in variable "foo" (could be anything really).
  const foo = this

  this.handleClick = function() {
    // Use "instance" instead of "this".
    console.log(foo.turn)
  };
}

或者,您可以使用function.bind()绑定this的值(即创建一个相同的函数,其this的值已经提前定义,而不是在调用时定义)。

function Game() {
  this.init = function() {
    for (let i = 0; i < this.tiles.length; i++) {
      // Tell the browser that when it calls handleClick, the value
      // of "this" is the one we provided in bind.
      this.tiles[i].addEventListener('click', this.handleClick.bind(this))
    }
  }
  this.handleClick = function() {
    console.log(this.turn); // returns undefined
  };
}

const game = new Game()
game.init()

请注意,此方法还取决于如何调用init(),因为它还确定init的{​​{1}}值是什么。如果我用不同的方式称呼它,如下所示:

this

const game = new Game() const init = game.init() init() 的{​​{1}}将是init(正常模式)或this(严格模式),这将导致绑定window使用该值。

答案 2 :(得分:1)

这里是基本解决方案

function Game() {
    this.tiles = document.getElementsByClassName('game-tile'),
    this.turn = 0;

    this.init = function() {
        let tile;
        for (let i = 0; i < this.tiles.length; i++) {
            tile = this.tiles[i];
            // reset game tiles
            tile.innerHTML = '';

            // setup event listeners
            // don't mix this for the node & this for the game
            // let's bind the context to the game, and the first param to the tile
            tile.addEventListener('click', handleClick.bind(this, tile));
        }
    };

    function handleClick(tile) {
        let id = parseInt(tile.id.replace('game-tile-', ''));
        console.log(id); // returns 0, 1, 2, etc.
        console.log(this.turn); // returns undefined
    };
}

let game = new Game();
game.init();

答案 3 :(得分:0)

有两种方法可以执行此操作,一种是将this保存到以后将要使用的变量中(我们称其为闭包):

例如:

const self = this;
this.handleClick = function() {
    const id = parseInt(this.id.replace('game-tile-', ''));
};

或调用bind,它将函数的this对象绑定到当前作用域的this

this.handleClick = function() {
    const id = parseInt(this.id.replace('game-tile-', ''));
};
this.handleClick = this.handleClick.bind(this);

PS:

如果可以使用ES6箭头功能:

this.handleClick = () => {
    // this will point to the scope where the function is declared
}

如果可以使用ES6类:

class Game(){
    constructor(){
        this.tiles = document.getElementsByClassName('game-tile'),
        this.turn = 0;
        for (let i = 0; i < this.tiles.length; i++) {
        // reset game tiles
        this.tiles[i].innerHTML = '';

        // setup event listeners
        this.tiles[i].addEventListener('click', this.handleClick);
    }

    handleClick = () => {
        let id = parseInt(this.id.replace('game-tile-', ''));
        console.log(id); // returns 0, 1, 2, etc.
        console.log(this.turn); // returns undefined
    }
}

使用ES6语法更好,因为对于阅读器和机器而言都更易于理解。如果您担心浏览器的兼容性,请使用BabelJS

这样的编译器