Фильтр массивов возвращает странные результаты
В связи с этим вопросом, я хотел попробовать этот
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
как собственные свойства.