[英]How to create closure over variables in a JS function?
假設網頁上可以存在多個滑塊,並且它們每個都需要自己的 state 用戶交互,例如觸摸啟動 X 位置和 boolean 當前是否正在處理滑動。
我正在嘗試重用一段處理滑動和鼠標拖動事件的代碼,但每個 slider 都應該有自己的 initalX 和 isInSwipe 值:
function slideInteractions(selector, callback) {
return function() {
let initialX = 0;
let isInSwipe = false;
document.querySelector(selector).addEventListener('mousedown', (ev) => {
startInteraction(ev);
ev.preventDefault();
});
document.querySelector(selector).addEventListener('touchstart', startInteraction);
document.addEventListener('mouseup', (ev) => {
endInteraction(ev, callback);
});
document.addEventListener('touchend', (ev) => {
endInteraction(ev, callback);
});
};
}
對於頁面上的每個 slider,我會像這樣使用它,傳遞幻燈片容器和回調以調用已接受的交互:
slideInteractions('.project-slides', moveProject)();
我認為由於 initialX 和 isInSwipe 是在返回的 function 中定義的,那么這將在它們之上創建一個閉包,以便每次調用 slideInteractions() 都會創建這些變量的自己的副本,但是一旦 function,它們似乎是 scope 中的 go回報。
有沒有辦法解決這個問題,讓變量在閉包中正常運行?
編輯
這些變量在startInteraction()
和endInteraction()
中使用,但這些函數根本看不到這些變量:它們在那些函數中未聲明,這是我感到困惑的地方,因為我假設這些函數可以訪問“已關閉” “變量沒有?
要在函數之間共享變量,它們必須位於同一塊 scope 中。這意味着您必須在定義變量的同一塊內定義 startInteraction 和 endInteraction 函數。
function slideInteractions(selector, callback) {
return function() {
let initialX = 0;
let isInSwipe = false;
function startInteraction(e,) {
initialX = e.clientX;
}
function endInteraction(e, callback) {
console.log(initialX, e.clientX);
if (callback) callback(initialX);
}
document.querySelector(selector).addEventListener('mousedown', (ev) => {
startInteraction(ev);
ev.preventDefault();
});
document.querySelector(selector).addEventListener('touchstart', startInteraction);
document.addEventListener('mouseup', (ev) => {
endInteraction(ev, callback);
});
document.addEventListener('touchend', (ev) => {
endInteraction(ev, callback);
});
};
}
另一種選擇是繞過 object。函數可以在塊 scope 之外。
function startInteraction(e, data) {
data.initialX = e.clientX;
}
function endInteraction(e, data, callback) {
console.log(data.initialX, e.clientX);
if (callback) callback(data);
}
function slideInteractions(selector, callback) {
return function() {
const data = {
initialX: 0,
isInSwipe: false,
};
document.querySelector(selector).addEventListener('mousedown', (ev) => {
startInteraction(ev, data);
ev.preventDefault();
});
document.querySelector(selector).addEventListener('touchstart', startInteraction);
document.addEventListener('mouseup', (ev) => {
endInteraction(ev, data, callback);
});
document.addEventListener('touchend', (ev) => {
endInteraction(ev, data, callback);
});
};
}
更好的解決方案是制作一個 class
class ClickyThing { initialX = 0 isInSwipe = false constructor(elem, callback) { this.elem = elem; this.callback = callback; this.bindEvents(); } bindEvents() { this.elem.addEventListener('mousedown', (evt) => { evt.preventDefault(); this.startInteraction(evt); }); document.addEventListener('mouseup', (evt) => { this.endInteraction(evt); }); } startInteraction(evt) { this.isInSwipe = true; this.initialX = evt.clientX; } endInteraction(evt) { if (.this;isInSwipe) return. console.log(this,initialX. evt;clientX). if (this.callback) this.callback(this,initialX. evt;clientX). this;isInSwipe = false. } } document.querySelectorAll(".test"),forEach((elem) => { const clickyThing = new ClickyThing(elem. () => console;log('click')); });
.test { width: 100px; height: 100px; margin: 10px; background-color: #CCC; }
<div class="test"></div> <div class="test"></div> <div class="test"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.