原型方法上的JS Array.prototype.filter

Jas*_*eck 5 javascript

有一种更简单的方法来在没有匿名函数的原型方法上调用过滤器吗?

我想知道是否有相同的myArray.filter(function(it){ it.method() }).

这看起来很接近可能有用的东西(它没有):

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

[new X(), new X()].filter(X.prototype.method.call);
Run Code Online (Sandbox Code Playgroud)

相反,我在最新的Firefox和Chrome中都遇到了TypeError,这是因为它不能完全按我的意愿行事:

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
Run Code Online (Sandbox Code Playgroud)

我尝试使用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);
Run Code Online (Sandbox Code Playgroud)

小智 6

让我们设置一些变量:

var method = X.prototype.method,
    array = [new X(), new X()];    
Run Code Online (Sandbox Code Playgroud)

您的尝试现在可以写成:

array.filter(method.call);
Run Code Online (Sandbox Code Playgroud)

问题是call被调用但没有this.它需要thismethod.method.call与原始产品完全相同Function.prototype.call,没有任何约束力this.仅仅说不method.call会给你一个版本的call约束method.安排call绑定到右边this,即method你需要绑定它:

array.filter(method.call.bind(method));
Run Code Online (Sandbox Code Playgroud)

走过这个:

  1. method.call.bind(method)返回Function#call绑定的新版本X#method; 把它想象成 method.call(waiting),等待用一个值来调用,该值将调用X#methodX的特定实例.

  2. 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}
Run Code Online (Sandbox Code Playgroud)

一些糖

人们可以用一个小包装器来使它更具语义和可读性,我们将调用它thisify:

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

array.filter(thisify(method));
Run Code Online (Sandbox Code Playgroud)

使用context参数来filter

您可以使用其中少用的context参数filter和它的兄弟(除了reduce),基本上,让filter你为你做绑定,如果你选择以这种方式看待它,因为

Array#filter(fn, context) === Array#filter(fn.bind(context))
Run Code Online (Sandbox Code Playgroud)

所以我们可以写:

array.filter(method.call, method);
Run Code Online (Sandbox Code Playgroud)

这对我来说实际上看起来更干净 我怀疑它是否会变得简单得多.