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

谁能帮助解释这个JavaScript算法[].filter.call(),javascript,arrays,filter,call,Javascript,Arrays,Filter,Call,我的任务是从字符串中按顺序接收唯一元素作为参数。我不明白这个函数uniqueElements如何返回['A','B','C','B'] var word = "AAAABBBBCCBB"; var uniqueElements = function(word) { return [].filter.call(word, (function(elem,index) { return word[index-1] !== elem })); } uniqueEl

我的任务是从字符串中按顺序接收唯一元素作为参数。我不明白这个函数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']
我查阅并阅读了以下资料:


但是没有成功。

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

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

var word=“AAAABBBBCCBB”;
var unique=word.split(“”).filter(函数(项、i、ar){
返回ar.indexOf(项目)==i;
}).加入(“”)
相当于

var uniqueElements = function(word) {
    return word.split("").filter(function(elem,index) {
        return word[index-1] !== elem
    });
}    
这应该更清楚了:它将单词转换成一个字符数组,然后过滤每个不同于前一个字符的字符。这解释了为什么“B”在结果中出现两次

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

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

如果您不了解代码的功能,可以记录操作!即

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));

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

return word.filter(function(elem,index) {
    return word[index-1] !== elem;
});
。。。如果
word
是一个数组,它将返回其中满足条件
word[index-1]!=elem
(是单词[index-1]!==word[index]
)的缩写,即与前面的字符不同的每个字符

但是,
filter
方法只存在于从
数组
原型继承的对象上,而字符串则不存在这种情况

但是,
filter
本身可以处理类似数组的对象,即具有
长度
且可能具有数字属性的对象。要调用
filter
而不使用真正的
Array
对象,可以对该函数使用
call
,然后提供上下文(即类似于Array的对象)作为第一个参数。其他参数保持不变。因此,您首先需要知道在哪里可以找到
过滤器
方法。。。它位于
数组中。prototype
,因此您可以这样引用它:

Array.prototype.filter
但是,由于所有数组都可以访问此方法,因此只获取一个空数组并引用其
过滤器
方法要短一些:

[].filter
return Array.from(word).filter(function(elem,index) {
    return word[index-1] !== elem
});
两者中的任何一个都会起作用。现在,您必须对其执行
调用
方法,并提供要迭代的类似数组的对象:

[].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
});
我将使用
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]);

控制台日志(uniques),用于将字符串转换为字符数组。语法“借用”数组方法,并将其应用于字符串。另请参见。这与在ES6世界中获得编译错误非常相似,可以更简洁易读地写成
[…word].filter
,或
Array.from(word).filter
。这忽略了他们这样做是为了将
filter
应用于字符串的全部要点。您可以传递字符串,因为此引用和筛选器函数将按预期执行拆分(“”)。这是可靠的行为吗?@ganqwerty它不是调用split,而是迭代字符串中的每个字母。字符串是可编辑的,因为它们实际上只是字符数组。