Javascript Array.prototype.filter意外输出

时间:2017-03-02 20:11:03

标签: javascript arrays

背景

最近我正在接受面试,有人让我参加考试:

var array = [1, 2, 3];
array[10] = 10;

alert(array.filter( n => n === undefined));

我确信这会警告一个7x未定义的数组,或者这些行之类的东西。

然而,它输出一个空数组,如长度为0的数组。

问题

对我而言,这是令人困惑的。有人可以帮我解释为什么会这样吗?

3 个答案:

答案 0 :(得分:8)

未访问已删除或未初始化(在稀疏数组上)项目。

Array#forEach

  

<强>描述

     

var array = [1, 2, 3, , , , , , , , 10]; console.log(array.filter((n, i) => (console.log(i), n === undefined)));按升序为数组中的每个元素执行一次提供的回调。对于已删除或未初始化的索引属性(即在稀疏数组上),不会调用它。

.as-console-wrapper { max-height: 100% !important; top: 0; }
{{1}}

答案 1 :(得分:1)

如果知道内部帮助,Array.prototype.filter(forEach,map,reduce)也会像这样排序(省略边界/角落检查):

Array.prototype.filter = function(fun/*, thisArg*/) {
    var arr = Object(this); 
    var len = arr.length;
    var res = [];

    for (var i = 0; i < len; i++) {
      if (i in arr) {
        var val = arr[i];

        if (fun.call(thisArg, val, i, arr)) {
          res.push(val);
        }
      }
    }

    return res;
}

关键是if循环中的for语句:

if (i in arr) { ... }

很明显,数组项目是“可过滤的”,必须明确声明/初始化这些项目并在key中关联prop / arr,这不适用于其他答案指出sparse array

<子> 注意:如果在控制台中运行var array = [1, 2, 3]; array[10] = 10;,则生成的稀疏数组如下所示:

Array[11]
  0: 1
  1: 2
  2: 3
  10: 10
  length: 11
  __proto__: Array[0]

答案 2 :(得分:0)

考虑到您设置的箭头功能,因为过滤器仅返回未定义的项目,但没有任何项目未定义,因此结果为空数组。但我想我知道你在哪里感到困惑。

array[10] = 10

不设置数组的长度。它将特定项设置为值10.因此,在此行之后,您将拥有一个包含4个元素的数组:1,2,3和... 10.

在数组中,您可以设置特定值的索引。如果省略它,它只会将1添加到最后一个索引。试试这个:

var array = [1, 2, 3];
array[10] = 10;

array.forEach( (value, index) => console.log(value, index));

JSFiddle:https://jsfiddle.net/eetmkd95/1/

你会看到它打印出来:

1 0 
2 1 
3 2 
10 10
为什么?因为如果你没有指定索引,它将基于+1增量生成一个索引,如果你指定,那么它会把你的值放在那个索引中。但是你要指定INDEX,而不是长度。 现在试试这个:

var array = [1, 2, 3];
array.length = 10;
array[8] = 10;

array.forEach( (value, ix) => console.log(value, ix));
console.log(array.length);

这怎么可能? length属性报告10而forEach只打印4行?这是因为a)forEach只显示实际存在于数组中并具有数字索引的项目,而b)长度不是非常可信。它仅适用于数字索引,并且仅当您未将其设置为更高的值时(如果您将其设置为较低的值,则它可以工作)。如果您使用字符串作为索引,它也不起作用。例如:

var array = [1, 2, 3];
array['myString'] =  10;

array.forEach( (value, ix) => console.log(value, ix));
console.log(array.length);

打印:

1 0
2 1
3 2
3

希望我澄清一点:)

你可以从Kyle Simpson的优秀系列丛书“你不懂JS”中深入理解这一点。关于这一点的部分在“Types&amp; Grammar”一书中,第44页,标题为“Array(..)”

这可能也很有用:http://www.2ality.com/2012/06/dense-arrays.html