除非为函数设计函数,否则不要将其用作回调

2021-02-06 20:21:02

//将一些数字转换成易于理解的字符串:从' some-library'中导入{toReadableNumber} ; const visibleNumbers = someNumbers。映射(toReadableNumber);

导出函数toReadableNumber(num){//以易于理解的形式将num作为字符串返回。 //例如10000000可能会变成' 10,000,000' }

一切正常,直到更新某些库,然后一切中断。但这并不是某些库的错误–他们从没有将ReadableNumber设计为要对array.map进行回调的方法。

//我们想到了:const visibleNumbers = someNumbers。映射(toReadableNumber); // ...就像:const visibleNumbers = someNumbers。映射((n)=> toReadableNumber(n)); //…但它更像是:const visibleNumbers = someNumbers。映射((item,index,arr)=> toReadableNumber(item,index,arr),);

我们还将数组中该项的索引以及数组本身传递给toReadableNumber。最初这很好用,因为toReadableNumber只有一个参数,但是在新版本中:

导出函数toReadableNumber(num,base = 10){//以易于理解的形式将num作为字符串返回。 //默认情况下以10为基数,但是可以更改。 }

toReadableNumber的开发人员认为他们正在进行向后兼容的更改。他们添加了一个新参数,并为其指定了默认值。但是,他们不希望某些代码已经使用三个参数来调用该函数。

toReadableNumber并不是被设计为array.map的回调,所以安全的做法是创建自己的函数以用于array.map:

就是这样! toReadableNumber的开发人员现在可以添加参数而不会破坏我们的代码。

该方法今天有效,因为requestAnimationFrame仅对第一个参数执行某些操作,但可能永远不会正确。可能会添加一个额外的参数,并且在更新的requestAnimationFrame附带的任何浏览器中,以上代码都可能中断。

如果有人在技术面试中问您这样做的结果,我建议您睁大眼睛然后走开。但是无论如何,答案是[-10,NaN,2,6,12,12],因为parseInt有第二个参数。

Chrome 90允许您使用AbortSignal删除事件侦听器,这意味着可以使用单个AbortSignal删除事件侦听器,取消提取以及任何支持信号的其他操作:

const controller = new(); const {信号} =控制器; el。 addEventListener(' mousemove&#39 ;, callback,{signal}); el。 addEventListener(' pointermove&#39 ;, callback,{signal}); el。 addEventListener(' touchmove',回调,{信号}); //稍后,删除所有三个监听器:controller。中止();

AbortController并非旨在作为addEventListener的选项对象。它之所以可以立即执行,是因为AbortController和addEventListener选项唯一的共同点是signal属性。

如果说将来AbortController获得controller.capture(otherController)方法,则侦听器的行为将发生变化,因为addEventListener将在capture属性中看到真实值,而capture是addEventListener的有效选项。

与回调示例一样,最好创建一个设计为addEventListener选项的对象:

const controller = new(); const options = {signal:controller .signal}; el。 addEventListener(名称,回调,选项); //虽然我发现当多个事物获得相同的信号时,这种模式更容易// const {signal} = controller; el。 addEventListener(名称,回调,{信号});

就是这样!注意将函数用作回调,将对象用作选项,除非它们是为这些目的而设计的。不幸的是,我不知道有一条规则可以捕捉到它(编辑:看起来有一条规则可以捕捉到某些情况,谢谢詹姆斯·罗斯!)

编辑:当我第一次发布此内容时,它在末尾有一点注释,表明TypeScript不能防止此问题,但是我仍然在Twitter上告诉我"只使用TypeScript&#34 ;,让我们更详细地了解它。

function toReadableNumber(num):string {//以易于理解的形式将num作为字符串返回。 //例如10000000可能会变成' 10,000,000'返回'' ; } const visibleNumbers = [1,2,3]。映射(toReadableNumber);

如果toReadableNumber更改为添加第二个字符串参数,则TypeScript会抱怨,但这不是示例中发生的情况。添加了一个附加的数字参数,它满足类型约束。

使用requestAnimationFrame示例会使情况变得更糟,因为在部署新版本的浏览器后而不是在部署项目的新版本时,这会出错。此外,TypeScript DOM类型往往要落后数月才能发布。

我认为,TypeScript应该强制传递给回调的参数数量,就像常规函数一样。至少,应该有一个选择。

接口{反向? :布尔值; }功能什么({反向=假}:选项= {}){控制台。 log(反向); }

您可以说,如果传递给对象的对象具有反向属性之外的其他属性,则TypeScript应该发出警告。但是在这个例子中:

…由于上面的对象是Object的实例,我们正在传递具有诸如toString,构造函数,valueOf,hasOwnProperty等属性的对象。似乎太过严格,无法要求这些属性是“拥有”的。属性(这不是运行时的工作方式),但也许TypeScript可以为Object附带的属性增加一些余地。

我是TypeScript的粉丝,此博客是使用TypeScript构建的,但不能解决此问题。