Чего я не понимаю, так это почему нельзя использовать функцию без вызова, созданную с помощью .call
[" foo", "bar "].map(String.prototype.trim.call);
Проблема в том, что всефункции наследуют один и тот же метод call
от Function.prototype
;таким образом, вышеприведенное эквивалентно
[" foo", "bar "].map(Function.prototype.call);
Для того, чтобы ваш код работал, call
необходимо будет "помнить", что вы получили его от String.prototype.trim
, а не от какой-либо другой функции;но это просто не то, как вызовы методов работают в JavaScript.В выражении вызова метода, таком как foo.bar()
, foo
- это не просто объект, свойство bar
которого вызывается как функция, это также объект, который неявно передается как this
в эта функция.В случае String.prototype.trim.call(x)
единственная причина, по которой call
знает, чтобы вызвать String.prototype.trim
, заключается в том, что вы используете синтаксис вызова метода, поэтому он может получить его из this
.
- Выше функция, возвращаемая
String.prototype.trim.call
, что делает?Что это за функция?
Это метод, который принимает объект и ноль или более аргументов и который при вызове функции вызывает эту функцию как метод этого объектапередавая эти аргументы.
Почему моя попытка с .call
не работает?
Потому что он пытается вызвать call
как свободную функцию, а не как метод;поэтому call
не получает аргумент this
, сообщающий ему, какую функцию вызывать, поэтому он не может выполнять свою работу.(Скорее всего, он получит «объект по умолчанию», например, window
, в качестве аргумента this
; но есть некоторые тонкости, в которых я не уверен. Вы можете попробовать [" foo", "bar "].map(function () { return this; })
в своем тестовом стенде, чтобы увидеть, что этодает вам в вашем окружении.)
Есть ли в любом случае сделать это с .bind
, .apply
или .call
?
Да;Вы можете написать:
[" foo", "bar "].map(Function.prototype.call.bind(String.prototype.trim))
, где Function.prototype.call.bind(String.prototype.trim)
- это функция, которая при вызове вызывает call
для String.prototype.trim
.(Другими словами, bind
обрабатывает «запоминание», что String.prototype.trim
- это объект, который вы хотите передать как this
.)
Тем не менее, я действительно думаю, что ваша оригинальная версия,
[" foo", "bar "].map(x => x.trim())
значительно выше.Если кто-то переопределил trim()
, вы должны верить, что это было по уважительной причине, и что вы действительно должны вызывать это переопределение вместо того, чтобы принудительно использовать унаследованное вместо него.