![](/img/trans.png)
[英]Javascript arrow function lexical scope: object literal vs “new” operator
[英]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.