4

我想创建一个可以正常调用的函数:

myFn(arg1, arg2)

或作为标记的模板文字:

myFn`text ${someVar}`

在 的实现中myFn,是否可以检测它是否被正常调用或作为标记模板文字?传递给模板文字的参数具有一定的模式(第一个参数是一个字符串数组,其他参数,如果存在的话,将比第一个参数中数组的长度少一个),所以我可以根据这一点进行检测. 但是理论上有人可以将相同的参数模式传递给正常的函数调用。

除了参数模式检测之外,是否有任何特殊的方法来检测它的调用方式?

4

2 回答 2

4

我认为没有任何方法可以绝对确定地进行检查,但是您可以在参数检查中添加一些内容,以减少意外使用满足您检查的参数调用它的可能性。如果作为模板标签调用,第一个参数将是一个包含至少一个元素的数组,它将被冻结,并且它将具有一个称为raw相同长度的数组的属性。正如您已经提到的,您还可以检查剩余参数的数量:

function myFn ( arg1, ...rest ) {
  const isTag = !!(
    arg1 && arg1.length > 0 && arg1.raw && arg1.raw.length === arg1.length &&
    Object.isFrozen( arg1 ) &&
    rest.length + 1 === arg1.length
  );

  console.log( isTag );
}

// isTag === true
myFn`test`;
myFn`${0} ${1}`;
myFn``;

// isTag === false
myFn( );
myFn( ['test'] );

您可以进一步验证数组和 in 中的元素raw是否都是字符串,甚至在用适当的字符替换原始字符串中的转义序列后检查它们是否是相同的字符串。我认为这可能是不必要的,因为它不会使某人更难故意欺骗您的功能(尽管它会限制他们可以用来欺骗它的输入),并且上述测试已经不太可能失败,除非有人试图故意欺骗它。

于 2019-07-04T16:40:39.277 回答
0

这是一个用 Typescript 编写的简短助手

export function is_tagged(a: any[]): a is [TemplateStringsArray, ...any[]] { // @ts-expect-error
    return a[0] instanceof Array && a[0].raw instanceof Array && a[0].length === a.length;
}

用法:

function foo(...args) {
    if (is_tagged(args)) {
        console.log("tagged!")
    } else {
        console.log("normal")
    }
}

foo("bar"); // "normal"
foo`bar`; // "tagged!"
于 2021-10-19T13:04:53.063 回答