如何在JavaScript的.filter()方法中向回调函数传递额外参数?

127

我想要将数组中的每个字符串与给定的字符串进行比较。我的当前实现方式是:

function startsWith(element) {
    return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith);

这个简单的函数可以工作,但只是因为目前 wordToCompare 被设置为全局变量,但我当然想避免这种情况并将其作为参数传递。我的问题是,我不确定如何定义 startsWith() 以便接受一个额外的参数,因为我真的不理解它所接受的默认参数是如何传递的。我尝试了我能想到的所有不同方式,但它们都不起作用。

如果您还能解释一下“内置”回调函数(对不起,我不知道这些的更好术语)如何传递参数,那就太棒了。


可能是将额外的参数传递给回调函数的重复问题。 - Bergi
8个回答

180

使 startsWith 接受待比较的单词并返回一个函数,该函数将被用作过滤器/回调函数:

function startsWith(wordToCompare) {
    return function(element) {
        return element.indexOf(wordToCompare) === 0;
    }
}

addressBook.filter(startsWith(wordToCompare));

另一个选择是使用Function.prototype.bind[MDN](仅在支持ECMAScript 5的浏览器中可用,对于旧版浏览器可以通过链接获取shim)并“修复”第一个参数:

function startsWith(wordToCompare, element) {
    return element.indexOf(wordToCompare) === 0;
}

addressBook.filter(startsWith.bind(this, wordToCompare));
我不太理解传递默认参数的方式。
没有什么特别的。在某个时刻,`filter` 只是调用回调函数并传递当前数组元素。因此这只是一个函数调用另一个函数,在这种情况下就是你作为参数传递的回调函数。
下面是类似函数的示例:
function filter(array, callback) {
    var result = [];
    for(var i = 0, l = array.length; i < l; i++) {
        if(callback(array[i])) {  // here callback is called with the current element
            result.push(array[i]);
        }
    }
    return result;
}

1
好的,现在我明白了。我之前试图直接将参数传递给回调函数... 我确实需要加强我的JavaScript技能。谢谢Felix,你的答案很有帮助。 - agente_secreto
传递额外的参数怎么办?我尝试传递一个参数数组,但好像失败了。 - geotheory
@geotheory:它们怎么样?你可以像其他函数一样传递多个参数。 - Felix Kling
在函数名后面加上bind(this)以及使用filter()链式调用帮助我在函数内部使用this。谢谢。 - Sagar Khatri
在第一个片段中,startsWith函数中的element是从哪里来的? - Masroor
@Prime:addressBook 看起来是一个数组。addressBook.filter 调用提供的函数,将数组的每个元素作为参数进行处理。可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter 。我回答中的最后一个示例展示了 .filter 的可能实现方式。 - Felix Kling

123

filter方法的第二个参数将在回调函数内部设置this

arr.filter(callback[, thisArg])

那么你可以这样做:

function startsWith(element) {
    return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);

8
我发现这是最佳答案。 - Jeaf Gilbert
那么现在新数组将被分配给wordToCompare对象,对吗?我如何使用wordToCompare对象稍后访问新数组? - Badhon Jain
3
@TarekEldeeb 刚刚传递了一个你制作的对象 {one: 'haha', two:'hoho'} - toddmo
2
这是一个很好的例子,说明答案在复杂性和混乱程度方面可能存在巨大差异,而它们可以非常简单。 - toddmo
当我尝试在ES6中使用thisArg时,它的值对我来说是未定义的。 - Erin
显示剩余2条评论

21

对于那些寻找使用箭头函数的ES6替代方法的人,你可以这样做。

let startsWith = wordToCompare => (element, index, array) => {
  return element.indexOf(wordToCompare) === 0;
}

// where word would be your argument
let result = addressBook.filter(startsWith("word"));

使用 includes 的更新版本:

const startsWith = wordToCompare => (element, index, array) => {
  return element.includes(wordToCompare);
}

有没有办法从元素、索引和数组中传递不同的参数?例如,我想传递一个X变量。 - imtk
@leandrotk 在这种情况下,“wordToCompare”是要传递的“X”变量。 - GetBackerZ

11
function startsWith(element, wordToCompare) {
    return element.indexOf(wordToCompare) === 0;
}

// ...
var word = "SOMETHING";

addressBook.filter(function(element){
    return startsWith(element, word);
});

5
您可以在过滤器中使用箭头函数,就像这样:

result = addressBook.filter(element => element.indexOf(wordToCompare) === 0);

MDN 上的箭头函数

箭头函数表达式相比函数表达式具有更短的语法,并且在词法上绑定 this 值(不绑定其自身的 this、arguments、super 或 new.target)。箭头函数始终是匿名的。这些函数表达式最适合非方法函数,并且不能用作构造函数。


注意:不支持IE。 - Luis Lavieri

1

如果有人想知道为什么他们的箭头函数忽略了[, thisArg],例如为什么

["DOG", "CAT", "DOG"].filter(animal => animal === this, "DOG") 返回[]

这是因为这些箭头函数内部的this在函数创建时被绑定,并设置为更广泛的封闭范围中this的值,因此忽略了thisArg参数。我通过在父级范围中声明一个新变量轻松解决了这个问题:

let bestPet = "DOG"; ["DOG", "CAT", "DOG"].filter(animal => animal === bestPet); => ["DOG", "DOG"]

这里有一些更多的阅读链接: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this


0

有一种简单的方法可以使用过滤函数,访问所有参数,而不会使它过于复杂。

除非回调函数的thisArg设置为另一个作用域,否则过滤器不会创建自己的作用域,我们可以在当前作用域内访问参数。如果需要,我们可以将“this”设置为定义不同作用域以访问其他值,但默认情况下它设置为从中调用的作用域。您可以在Angular作用域在此堆栈中中看到使用了this

使用indexOf会破坏过滤器的目的,并增加更多开销。过滤器已经遍历了数组,那么为什么我们还需要再次迭代呢?相反,我们可以将其变成一个简单的纯函数

以下是React类方法中使用的用例场景,其中状态具有名为items的数组,通过使用过滤器,我们可以检查现有状态:

checkList = (item) => {  // we can access this param and globals within filter
  var result = this.state.filter(value => value === item); // returns array of matching items

  result.length ? return `${item} exists` : this.setState({
    items: items.push(item) // bad practice, but to keep it light
  });
}

0

基于oddRaven的回答和https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

我用了两种不同的方法。 1)使用函数方式。 2)使用内联方式。

//Here  is sample codes : 

var templateList   = [
{ name: "name1", index: 1, dimension: 1 }  ,
{ name: "name2", index: 2, dimension: 1 }  ,
{ name: "name3", index: 3, dimension: 2 }  ];


//Method 1) using function : 

function getDimension1(obj) {
                if (obj.dimension === 1) // This is hardcoded . 
                    return true;
                else return false;
            } 

var tl = templateList.filter(getDimension1); // it will return 2 results. 1st and 2nd objects. 
console.log(tl) ;

//Method 2) using inline way 
var tl3 = templateList.filter(element => element.index === 1 || element.dimension === 2  ); 
// it will return 1st and 3rd objects 
console.log(tl3) ;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接