这个unique()函数如何工作

时间:2017-01-08 16:07:35

标签: javascript arrays filter

当我看到我找到的unique()函数时 它将一个数组作为参数并返回一个包含该数组的唯一元素的新数组(这意味着没有重复的项)。但是我无法理解这个功能的逻辑。有人可以向我解释一下吗?

这是功能:

function unique ( array ) {
    return array.filter(function(a){
        return !this[a] ? this[a] = true : false;
    }, {});
}

我无法真正理解整个代码,特别是!this[a] ? this[a] = true : false;和新对象({})作为filter的第二个参数传递。

4 个答案:

答案 0 :(得分:3)

让我们从filter开始:

  

filter()方法创建一个包含所有传递元素的新数组   由提供的函数实现的测试。

a是应用过滤器的数组的随机数。整个要点如下:

return !this[a] ? this[a] = true : false;

如果this[a]为真,则a已经处理过一次,并且已作为其属性之一添加到此this[a]。否则,a为false。因此,将其否定结果设为true,并返回当前this[a]。此外,a将设置为true,然后我们将继续执行下一个filter

以下代码段将帮助您了解var numbers = [1,2,3,4,5]; var filteredNumbers = numbers.filter(function(number){ console.log(number); return number > 2; }); console.log(filteredNumbers);的作用:



unique




以下代码段将向您展示function unique ( array ) { return array.filter(function(a){ console.log(this); return !this[a] ? this[a] = true : false; }, {}); } var array = [1,2,3,1,2,3,4,5,5,6]; console.log(unique(array));函数中发生的事情:



filter




  

我理解过滤器的基本逻辑,但我不是{}   作为第二个参数传递,以及每个值如何添加到新数组   用!这[a]

第二个参数是可选值,您可以将其传递给this方法,并且可以在执行回调时将其用作filter(检查我在开头提到的关于this)的链接。你传递一个空对象。在回调中使用关键字{}时,请引用此对象。这就是为什么代码第一次进入此方法会返回!this[1]。检查第二个代码段输出的第一行。

我将根据第二个片段解释您问题的第二部分。第一次进入时你有一个空对象(我指的是这个),处理的第一个数字是1.所以这个1将是未定义的。所以?是真的。因此执行this[1] = true. 后的第一部分是作业

this

现在true获得了第一个密钥1,其值为!this[1] 。此外,1将从过滤器返回。同样的情况发生在2和3.当我们到达1时

this[1]

是假的,因为private class Scan extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); mpd = new ProgressDialog(CatalogActivity.this); mpd.setTitle(HomeActivity.name); mpd.setMessage("Searching for items..."); mpd.setIndeterminate(false); mpd.show(); } @Override protected Void doInBackground(Void... voids) { scanExpression = new DynamoDBScanExpression(); Condition condition = new Condition() .withComparisonOperator(ComparisonOperator.CONTAINS) .withAttributeValueList(new AttributeValue(HomeActivity.id)); scanExpression.addFilterCondition("productId", condition); result = HomeActivity.mapper.scan(Product.class, scanExpression); arraylist = new ArrayList<Product>(); for (Product prod : result) { prod.setName(prod.getName()); prod.setPrice(prod.getPrice()); prod.setProductId(prod.getProductId()); prod.setSummary(prod.getSummary()); prod.setSale(prod.getSale()); prod.setSalePrice(prod.getSalePrice()); arraylist.add(prod); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); lv = (ListView) findViewById(R.id.itemsListView); adapter = new ListViewAdapter(CatalogActivity.this, arraylist); lv.setAdapter(adapter); mpd.dismiss(); } } 是真的。因此返回false并且现在不会将1添加到将在处理完所有数组元素后返回的数组中。

答案 1 :(得分:2)

基本上,.filter会通过提供迭代数组的各个值来调用callBack函数。如果callBack返回一个解析为true的值,那么将收集该值,否则将忽略该特定值。

这里使用了filter的第二个参数。第二个参数将在内部调用this时用作上下文(callBack)。因此,在您的代码中,传递的对象将添加数组的值作为每次迭代的属性。在连续迭代中,代码将检查当前值是否在最初传递的对象中作为property可用。如果可用,则该三元运算符将返回false,否则返回true

因此,将从过滤器函数返回唯一值。

答案 2 :(得分:0)

Array.filter只会在函数传递返回truthy时获取数组的元素。

对于数组的每个元素,它正在执行

return !this[a] // if value is not yet on this
  ? this[a] = true  // add value to this and return true (grab element)
  : false;  // value was already cached, so return false (don't grab)

所以它只返回每个

中的1个

答案 3 :(得分:0)

其他答案基本上解释了这是如何工作的。但有几点:

首先,代替return !this[a] ? this[a] = true : false;,编写

会更简洁
!this[a] && (this[a] = true)

其次,这个代码有一个缺陷,它只适用于可以作为对象键的元素 - 基本上是字符串或数字。这就是使用Set更好的原因:

Array.from(new Set(array))

以上内容适用于任何原始对象。

第三,这种方法对字符串和数字不起作用。如果数字1存在,则会过滤掉字符串"1"

const uniq = a => a.filter(x => !this[x] && (this[x] = true), {});
console.log(uniq([1, '1']));

原因是对象键是字符串值的。

最后,恕我直言,这段代码对于自己的好处来说有点太棘手了。大多数开发人员,即使是经验丰富的开发人员,在弄清楚之前会停下来并抓住他们的头脑。缺乏经验的开发人员必须先查阅thisArg参数的文档,然后才能理解它Array#filter。内部分配的三元运算符也有点神秘。我会继续把它写成

if (this[x]) return false;
this[x] = true;
return true;