Фильтр массивов возвращает странные результаты

В связи с этим вопросом, я хотел попробовать этот

var arr = [0,1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]];
arr.filter(Object.hasOwnProperty,"abc");//outputs [0, 1, 2]
arr.filter(Object.hasOwnProperty,"2222222") //[0, 1, 2, 4, 6]

Кто-нибудь знает, почему фильтр возвращает эти значения? Спецификация фильтра и MDN doc также не ясно, как используется второй аргумент фильтра.

Ответ 1

Второй аргумент Array.prototype.filter - это значение, которое будет установлено как this для функции, которая передается в качестве первого аргумента.

Итак, ваш код заканчивается, чтобы быть чем-то вроде:

arr.filter(function(v, i, a) {
    return Object.hasOwnProperty.call("222", v, i, a);
});

Поэтому он в основном проверяет, имеет ли строка "222" свойства, которые вы перечисляете в массиве.

Из этого становится понятно, почему найдены свойства 0, 1 и 2 - так как это индексы символов в строке "222" и, скажем, 9 или {"abc":123} не являются - поскольку строка "222" не имеет таких свойств.

Это та же история с более длинной строкой, которая также включает свойства 4 и 6 только потому, что она длиннее.

Некоторые примеры:

Object.hasOwnProperty.call("222", 1); // true, because `"222"[1]` is there
Object.hasOwnProperty.call("222", 'foo'); // false, because `"222"['foo']` is not there

Ответ 2

Это кристально ясно из спецификации

Array.prototype.filter ( callbackfn [ , thisArg ] ),

Если задан параметр thisArg, он будет использоваться как значение thisдля каждого вызова callbackfn.

Итак:

var arr = [0,1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]];
arr.filter(Object.hasOwnProperty,"2222222");

переводит на эти вызовы в последовательности

"2222222".hasOwnProperty(0);             // true     -> 0
"2222222".hasOwnProperty(1);             // true     -> 1
"2222222".hasOwnProperty(2);             // true     -> 2
"2222222".hasOwnProperty(true);          // false    -> 
"2222222".hasOwnProperty(4);             // true     -> 4
"2222222".hasOwnProperty({"abc":123});   // false    -> 
"2222222".hasOwnProperty(6);             // true     -> 6
"2222222".hasOwnProperty(7);             // false    -> 
"2222222".hasOwnProperty({"def":456});   // false    -> 
"2222222".hasOwnProperty(9);             // false    -> 
"2222222".hasOwnProperty([10]);          // false    -> 
                                         // filter() => [0,1,2,4,6]

Строки, где указано true, связаны с тем, что строки могут быть проиндексированы в подобные массивы, поэтому строка с двумя символами имеет индексы 0 и 1 как собственные свойства.