Как определить, была ли функция вызвана нормально или как теговый литерал шаблона?

Я хотел бы создать функцию, которую можно вызывать нормально:

myFn(arg1, arg2)

Или как помеченный литерал шаблона:

myFn`text ${someVar}`

Можно ли в реализации myFn определить, был ли он вызван обычным образом или как теговый литерал шаблона? Аргументы, передаваемые литералу шаблона, имеют определенный шаблон (первый аргумент — это массив строк, дополнительные аргументы, если они существуют, будут на единицу меньше, чем длина массива в первом аргументе), поэтому я мог определить на основе этого . Но теоретически кто-то может передать тот же шаблон аргумента в обычный вызов функции.

Есть ли какой-то особый способ определить, как это было вызвано, кроме обнаружения шаблона аргумента?


person maxedison    schedule 04.07.2019    source источник
comment
нет, а зачем различать?   -  person Thomas    schedule 04.07.2019
comment
Я не думаю, что есть какой-либо способ обнаружить это с абсолютной уверенностью, но вы можете добавить некоторые вещи к своим проверкам аргументов, чтобы уменьшить вероятность случайного вызова с аргументами, которые удовлетворяют вашим проверкам. НАПРИМЕР. Первый аргумент — это массив, но он также заморожен, поэтому вы можете проверьте это, и у него также есть свойство raw, которое представляет собой массив той же длины.   -  person Paul    schedule 04.07.2019
comment
@Paulpro, это отличная информация, и она делает проверку аргументов настолько надежной, что это было бы достаточным решением. Не стесняйтесь предлагать это в качестве ответа!   -  person maxedison    schedule 04.07.2019
comment
Хорошо, я добавил ответ.   -  person Paul    schedule 04.07.2019
comment
Нет, нет специального способа обнаружить это. Для чего вам это нужно?   -  person Bergi    schedule 04.07.2019


Ответы (1)


Я не думаю, что есть какой-либо способ проверить с абсолютной уверенностью, но вы можете добавить некоторые вещи к своим проверкам аргументов, чтобы уменьшить вероятность случайного вызова с аргументами, которые удовлетворяют вашим проверкам. При вызове в качестве тега шаблона первым аргументом будет массив, содержащий хотя бы один элемент, он будет заморожен и будет иметь свойство с именем 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'] );

Вы можете пойти немного дальше, проверив, что все элементы в массиве и в raw являются строками, и даже проверить, что они являются одними и теми же строками, заменив escape-последовательности в необработанных строках соответствующими символами. Я думаю, что это, вероятно, не нужно, потому что кому-то не будет сложнее целенаправленно обмануть вашу функцию (хотя это ограничит входные данные, которые они могут использовать, чтобы обмануть ее), и уже маловероятно, что приведенный выше тест не пройден, если только кто-то пытается целенаправленно обмануть его.

person Paul    schedule 04.07.2019
comment
Мне не хватает Array.isArray чека (или двух). Затем вы можете удалить файл arg1 && arg1.length > 0. - person Bergi; 04.07.2019