Строковые методы с функциями более высокого порядка
Я столкнулся с странной вещью, пытаясь использовать методы 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.
В этом случае функция обертки неизбежна для получения желаемого поведения.