簡體   English   中英

有沒有辦法使用命名箭頭 function 在 object 中維護詞匯 scope?

[英]Is there a way to use named arrow function to maintain lexical scope inside an object?

描述:我正在使用window.addEventListener()並想調用一個命名的 function (不是匿名函數),因為我希望能夠在稍后階段使用 removeEventListener 。但是,eventHandler 中的console.log是一個箭頭 function 顯示“this”仍然指向 window object 而不是游戲 ZA8CFDE6331BD54B66AC96F8911。

PS:忽略代碼的其他部分,因為我正在重構它,rest 可能仍然不完整,我知道我可以使用構造函數,但我處於學習階段,在我研究構造函數之前,我想看看這是否可以完成沒有構造函數

function makeGameObject() {

  return {

    score: 0,
    level: 1,


    start() {
      for (let coin of coins) {
        this.moveCoin(coin);
      }
      window.addEventListener("keydown", this.gameOn)
    },

    stop() {
      window.removeEventListener("keydown", this.gameOn);

    },


    gameOn: (evt) => {
      console.log(this);
      if (evt.key.toUpperCase() === "W" || evt.key === "ArrowUp") {
        this.moveObject(player, 30, 'up');
      } else if (evt.key.toUpperCase() === "S" || evt.key === "ArrowDown") {
        this.moveObject(player, 30, 'down');
      } else if (evt.key.toUpperCase() === "A" || evt.key === "ArrowLeft") {
        this.moveObject(player, 30, 'left');
        player.style.transform = 'scale(-1,1)';
      } else if (evt.key.toUpperCase() === "D" || evt.key === "ArrowRight") {
        this.moveObject(player, 30, 'right');
        player.style.transform = 'scale(1,1)';
      }

      for (let coin of coins) {
        if (this.isTouching(player, coin)) {
          this.moveCoin(coin);
          score++;
          h1.innerText = score;
        }
      }
    },

這是對 function 的調用:

const player = document.querySelector("#player");
const coins = document.querySelectorAll(".coin");
const body = document.querySelector("body");
const h1 = document.querySelector("h1");

const game = makeGameObject();
game.start();

一種方法是動態創建gameOn()的綁定版本並使用它來代替:

{
  // ...

  start() {
    for (let coin of coins) {
      this.moveCoin(coin);
    }
    if (this.boundGameOn === undefined) {
      this.boundGameOn = this.gameOn.bind(this);
    }
    window.addEventListener("keydown", this.boundGameOn)
  },

  stop() {
    window.removeEventListener("keydown", this.boundGameOn);
  },

  // ...
}

理想情況下,您會在構造函數中執行此操作。 如果你有一個構造函數而不是 object 文字,你可以這樣做:

function GameObject () {
  this.boundGameOn = this.gameOn.bind(this)
}

GameObject.prototype = {
  // rest of code ..
}

事實上,在 React 應用程序中,這種設計模式並不少見:

function GameObject () {
  this.gameOn = this.gameOn.bind(this); // MAGIC!!
}

GameObject.prototype = {
  // ...

  start() {
    for (let coin of coins) {
      this.moveCoin(coin);
    }
    window.addEventListener("keydown", this.gameOn)
  },

  stop() {
    window.removeEventListener("keydown", this.gameOn);
  },

  // ...
}

MAGIC行確保this內部gameOn()始終指向游戲 object,因為您正在用其自身的綁定版本覆蓋它。

這在 ES6 class 語法中看起來稍微干凈一些(只是稍微有點,我個人對這兩種語法都沒有偏好):

class GameObject {

  constructor () {
    this.gameOn = this.gameOn.bind(this); // MAGIC!!
  }

  // ...

  start() {
    for (let coin of coins) {
      this.moveCoin(coin);
    }
    window.addEventListener("keydown", this.gameOn)
  }

  stop() {
    window.removeEventListener("keydown", this.gameOn);
  }

  // ...
}

With the experimental class property syntax proposed for ES7 it's even simpler: you can just use an arrow function (don't use this directly for now, mid-2020, because Safari does not support this but if you use Babel or Typescript you can compile低至 ES6):

class GameObject {
  // ...

  start = () => {
    for (let coin of coins) {
      this.moveCoin(coin);
    }
    window.addEventListener("keydown", this.gameOn)
  }

  stop = () => {
    window.removeEventListener("keydown", this.gameOn);
  }

  // ...
}

this情況下,它受箭頭 function 的約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM