Строковые методы с функциями более высокого порядка

Я столкнулся с странной вещью, пытаясь использовать методы String с функциями более высокого порядка. Это вызовет ошибку:

['a', 'b'].some('boo'.includes)

Я должен обернуть предикат в другую функцию, чтобы заставить ее работать. Но не 'boo'.includes уже функцию?

Это работает с простыми функциями:

const boo = {
    includes: () => true
};

['a', 'b'].some(boo.includes)

Есть ли какое-то специальное свойство методов String, которое мешает им быть таким, как это?

Ответы

Ответ 1

"boo".includes - это не что иное, как String.prototype.includes. Однако вызов его в строке "boo" устанавливает this в "boo", что дает правильный контекст функции. Например, "boo".includes("b") совпадает с String.prototype.includes.call("boo", "b").

Передача его в качестве аргумента, например ['a', 'b'].some('boo'.includes), такая же, как ['a', 'b'].some(String.prototype.includes), которая тогда не хватает должного this как контекста.

Конечно, вы можете использовать, например, bind: ['a', 'b'].some(String.prototype.includes.bind("boo")) или использовать необязательный второй параметр thisArg для some: ['a', 'b'].some(String.prototype.includes, "boo"). Это избавит вас от ошибки. Однако вы заметите, что some пропускают не только элемент, но и индекс как второй параметр, а сам массив как третий. Это проблема, так как includes также второй необязательный параметр для начальной позиции. Это вызывает вероятное нежелательное поведение, например, элемент массива "b" находится в индексе 1, а "boo".includes("b", 1) === false.

В общем, вам нужна функция, которая настолько отличается от String.prototype.includes, что просто проще обернуть ее в новую функцию, которая фактически делает то, что вы хотите: ['a', 'b'].some(e => "boo".includes(e)), как вы уже заметили.

Ответ 2

Комментарий Скотта Маркуса неверен. Это абсолютно нормально в функциональном программировании, чтобы обойти функции без их необходимых аргументов. Здесь актуальная проблема:

Обратный вызов вы передаете some вызывается с тремя аргументами: currentValue, index и array, и его this устанавливается на undefined, если вы не передать второй параметр в some. Метод String.prototype.includes принимает два аргумента: search и start, и его this используется как строка для поиска. В результате этого взаимодействия includes вызов, вызываемый без строки для поиска, поэтому он дает ошибку.

Даже если вы исправьте вышеперечисленное через bind или, передав второй параметр some, это не полностью устранит проблему. Вторая половина проблемы - второй аргумент. some считает, что это index, но includes в start includes считают его start. В результате, b не будет искать до второго символа строки, поэтому, даже если ошибка исчезнет, тест все равно вернет false.

В этом случае функция обертки неизбежна для получения желаемого поведения.