Подтвердить что ты не робот

JS Array.prototype.filter на прототипе метода

Есть ли более простой способ вызвать фильтр на прототипе без анонимной функции?

Интересно, есть ли эквивалент myArray.filter(function(it){ it.method() }).

Это похоже на то, что может работать (это не так):

function X() {}
X.prototype.method = function() { console.log(this); }

[new X(), new X()].filter(X.prototype.method.call);

Вместо этого я получаю TypeError как в последнем Firefox, так и в Chrome, потому что он не совсем делает то, что я хочу:

x = function() { console.log(this) }
x.call(123) //logs 123
y = x.call //reports that y is of type function in console
y(123) //TypeError: Function.prototype.call called on incompatible undefined
y.call(x, 123); //this is what you really need

Я попытался использовать bind, возможно, я его пропустил, но если это не однострочный шрифт, это не лучше, чем форма анонимного метода:

function X() {}
X.prototype.method = function() { console.log(this); }

y = X.prototype.method.call
y.bind(X.prototype.method)

[new X(), new X()].filter(y);
4b9b3361

Ответ 1

Пусть заданы некоторые переменные:

var method = X.prototype.method,
    array = [new X(), new X()];    

Теперь ваша попытка может быть записана как:

array.filter(method.call);

Проблема заключается в том, что call вызывается, но без this. Для этого требуется this method. method.call точно совпадает с raw Function.prototype.call, без привязки к какому-либо this. Простое выражение method.call не дает вам версию call, привязанную к method. Чтобы упорядочить привязку call к правой части this, а именно method, вам необходимо связать ее:

array.filter(method.call.bind(method));

Просматривая это:

  • method.call.bind(method) возвращает новый версия Function#call, привязанная к X#method; подумайте об этом как о method.call(waiting), который ожидает вызова с помощью значение, которое вызовет X#method для конкретного экземпляра X.

  • Array#filter передает каждый аргумент в массив этой связанной версии из Function#call, что приводит к method.call(elt, remaining_args...), что эквивалентно elt.method(remaining_args...).

Вывод:

> array.filter(method.call.bind(method));
  X {method: function}
  X {method: function}

Некоторые сахара

Можно было бы сделать это более семантическим и читаемым с помощью небольшой обертки, которую мы будем называть thisify:

function thisify(fn) { return fn.call.bind(fn); }

array.filter(thisify(method));

Используя параметр context в filter

Вы можете использовать малоиспользуемый параметр context filter и его собратьев (кроме reduce), по существу, позволяя filter выполнять для вас, если вы решите посмотреть на него таким образом, поскольку

Array#filter(fn, context) === Array#filter(fn.bind(context))

Итак, мы можем просто написать:

array.filter(method.call, method);

Это на самом деле выглядит более чистым для меня. Я сомневаюсь, что это может стать намного проще.