自定义去抖动功能不适用于匿名功能

时间:2018-11-21 15:48:28

标签: javascript anonymous-function

我正在尝试创建一个自定义的反跳功能:

const debounced = [];

const cancelFunc = timeout => () => {
  clearTimeout(timeout);
};

function debounce(fn, wait, ...args) {  
  let d = debounced.find(({ func }) => func === fn);

  if (d) {
    d.cancel();  
  } else {
    d = {};
    debounced.push(d);
  }

  d.func = fn;   
  d.timeout = setTimeout(fn, wait, ...args);
  d.cancel = cancelFunc(d.timeout);
}

如果我使用命名函数,它将按预期工作:

debounce(foo, 1000); // called once with 5 clicks in 1 second

但是我无法使其与匿名函数一起使用:

debounce(() => { foo(5); }, 1000); // called 5 times with 5 clicks in 1 second

我在这里创建了一支笔:https://codepen.io/anon/pen/gQvMdR?editors=1011

2 个答案:

答案 0 :(得分:2)

发生这种情况是由于您的find条件。让我们备份一下,考虑一下这段代码:

if (
    (function(){ return 1 }) === (function(){ return 1 })
) {
    console.log('The functions are equal');
} else {
    console.log('The functions are NOT equal');
}

// logs 'The functions are NOT equal'

即使我编写了两个相同的匿名函数,但它们并非严格相等。当您传递该匿名函数时,实际上就是您在做什么。因此,当您在数组中搜索先前找到的函数时,它将永远不会找到匹配项,因为每次调用debounce(() => { foo(5); }, 1000);都会创建一个新函数。由于它永远不会找到匹配项,因此永远不会被取消。

答案 1 :(得分:0)

如@SLaks 所述,“每次调用都会创建一个单独的函数,因此您不会在数组中找到它。”

因此,您只需要在数组中存储一些内容以使其匹配即可,就可以使用.toString()

// ================

const debounced = [];

const cancelFunc = timeout => () => {
  clearTimeout(timeout);
};

function debounce(fn, wait, ...args) {
  let d = debounced.find(({ funcString }) => funcString === fn.toString());

  if (d) {
    d.cancel();
  } else {
    d = {};
    debounced.push(d);
  }

  d.func = fn;
  d.funcString = fn.toString()
  d.timeout = setTimeout(fn, wait, ...args);
  d.cancel = cancelFunc(d.timeout);
}

// ================

function foo(value) {
	console.log('value:', value)
}

function onClickBroken() {
  debounce(() => { foo(5); }, 1000);
}
<button onClick="onClickBroken()">Click me 5 times</button>