谁可以帮助解释这个JavaScript算法[].filter.call()

Who can help to explain this JavaScript algorithm [].filter.call()

本文关键字:filter call 算法 JavaScript 帮助 解释      更新时间:2023-09-26

我的任务是按字符串作为参数的顺序接收唯一元素。我不明白这个函数 uniqueElements 如何返回['A','B','C','B'] .

var word = "AAAABBBBCCBB";
var uniqueElements = function(word) {
    return [].filter.call(word, (function(elem,index) {
        return word[index-1] !== elem
    }));
}    
uniqueElements(word);      
//it should return ['A','B','C','B']

我检查并阅读了以下来源:

MDN Mozilla和JS博客,但没有成功。

这里[].filter.call的目的是在字符串上应用 filter 方法。天真地,你会首先尝试这样做:

return word.filter(function(elem,index) {
    return word[index-1] !== elem;
});

。如果word是一个数组,它将返回其中满足条件word[index-1] !== elem(word[index-1] !== word[index]的缩写(的字符,即每个字符都与它前面的字符不同。

但是,filter 方法仅存在于从Array原型继承的对象上,字符串并非如此。

但是,filter本身可以处理类似数组的对象,即具有length并且可能具有数字属性的对象。要在没有真正的Array对象的情况下调用filter,可以在该函数上使用call,然后提供上下文(即类似数组的对象(作为第一个参数。其他参数保持不变。所以你首先需要知道在哪里可以找到filter方法......它在 Array.prototype 上,所以你会像这样引用它:

Array.prototype.filter

但是由于所有数组都可以访问此方法,因此仅获取一个空数组并引用其filter方法会更短:

[].filter

两者中的任何一个都可以工作。现在,您必须在其上执行 call 方法,并提供要迭代的类似数组的对象:

[].filter.call(words, ...)

其余的就像你对真数组所做的那样:你提供回调函数:

return [].filter.call(word, function(elem,index) {
    return word[index-1] !== elem
});

返回值不再是字符串。它 - 就像filter总是返回 - 一个数组:一个真实的数组 - 它是由filter方法创建的。

ES6 方式:

在 ES6 中,你可以用更易读的方式编写它,因为现在有 Array.from 方法,它可以将类似数组的对象转换为真正的数组。然后你可以继续使用filter方法:

return Array.from(word).filter(function(elem,index) {
    return word[index-1] !== elem
});

点差运算符是 ES6 提供的另一种选择:

return [...word].filter(function(elem,index) {
    return word[index-1] !== elem
});
var uniqueElements = function(word) {
    return [].filter.call(word, (function(elem,index) {
        return word[index-1] !== elem
    }));
}    

相当于

var uniqueElements = function(word) {
    return word.split("").filter(function(elem,index) {
        return word[index-1] !== elem
    });
}    

这应该已经更清楚了:它将单词转换为 char 数组,然后过滤与前一个不同的每个字符。这就解释了为什么"B"在结果中出现两次。

要获得独特的元素,您可以这样做

var uniqueElements = function(word) {
    var res = []
    word.split("").forEach(function(val){
        if (res.indexOf(val)===-1) res.push(val);
    });
    return res
}  

它对数组对象的过滤器方法执行显式call(),以便它们可以传入字符串。他们只是使用[]而不是Array因为它的语法较短,或者有人在编写时试图变得聪明。

通常,filter() 方法会影响数组本身的内容。但是,通过call() -ing 它,您可以通过传入另一个数组或在本例中传递一个字符串(被视为字符数组(来更改上下文。然后,它为每个元素运行提供的函数,如果函数的返回值为 true,则保留该元素。

如果你不明白代码是做什么的,你可以记录操作!IE

var word = "AAAABBBBCCBB";
function uniqueElements(word){
    return [].filter.call(word,(
        function(elem,index) { 
        console.log("Index : "+index+" | Elem : " +elem+" | CompareTo "+word[index-1]);
            return word[index-1] !== elem;
        }
    ));
}
uniqueElements(word); 

您将获得以下输入:

Index : 0 | Elem : A | CompareTo undefined
Index : 1 | Elem : A | CompareTo A
Index : 2 | Elem : A | CompareTo A
Index : 3 | Elem : A | CompareTo A
Index : 4 | Elem : B | CompareTo A
Index : 5 | Elem : B | CompareTo B
Index : 6 | Elem : B | CompareTo B
Index : 7 | Elem : B | CompareTo B
Index : 8 | Elem : C | CompareTo B
Index : 9 | Elem : C | CompareTo C
Index : 10 | Elem : B | CompareTo C
Index : 11 | Elem : B | CompareTo B

使用它,您可以检查每个不等于前一个元素的元素是否发送到您的数组。

很少有答案/评论已经指出了[].filter.call((是如何工作的。

如果要获取字符串而不是数组,只需.join("") IE添加

即可
var word = "AAAABBBBCCBB";
function uniqueElements(word){
    return [].filter.call(word,(
        function(elem,index) { 
        console.log("Index : "+index+" | Elem : " +elem+" | CompareTo "+word[index-1]);
            return word[index-1] !== elem;
        }
    )).join("");
}
uniqueElements(word); 

为了更好地理解,我将代码分成带有内联注释的较小部分。

var word = "AAAABBBBCCBB";
var uniqueElements = function(word){
    // this is the filter function
    // this function will get each element of the string with its index
    var filterFunction = function(elem, index) {
        // the elements who pass the following condition are kept
        // the condition - 
        // if the character at the previous index (index-1) is not equal to the 
        // current element, then keep the element
        return word[index-1] !== elem;
    }
    // the below is equivalent to Array.prototype.filter.call(context, filterFunction)
    return [].filter.call(word, filterFunction);
}
console.log(uniqueElements(word));

我会通过如下方式利用Array.prototype.reduce()来做这个 O(n( 时间;

var str = "AAAABBBBCCBB",
uniques = Array.prototype.reduce.call(str, (p,c,i) => i-1 ? p[p.length-1] !== c ? (p.push(c),p)
                                                                                : p
                                                          : [c]);
console.log(uniques);

var word = "AAAABBBBCCBB";
var unique = word.split('').filter(function(item, i, ar) {
  return ar.indexOf(item) === i;
}).join('');