2017-01-08 3 views
2

Как я и искал функцию unique(), я нашел , которая принимает массив как аргумент и возвращает новый массив, который содержит уникальные элементы этого массива (что означает отсутствие дублированных элементов). Однако я не могу понять логику этой функции. Может ли кто-нибудь объяснить это мне?Как работает эта функция unique()

Вот функция:

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

Я не могу понять весь код особенно !this[a] ? this[a] = true : false; и новый объект ({}), который передается в качестве второго аргумента filter.

ответ

2

Давайте начнем с filter:

Фильтр() создает новый массив со всеми элементами, которые проходят тест, реализованный предоставленной функцией.

a - это случайное число массива, к которому применяется фильтр. Вся суть заключается в следующем утверждении:

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

this[a] Если это верно, то a уже был обработан один раз, и он был добавлен к этому в качестве одного из его свойств. В противном случае this[a] является ложным. Таким образом, результат его отрицания верен, и текущий a должен быть возвращен. Кроме того, значение this[a] будет равно true, а затем мы перейдем к следующему a.

Следующий фрагмент кода поможет вам понять, что 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));

Я понимаю основную логику фильтра, но то, что я не является {} передается в качестве 2-го аргумента, и как каждое значение добавляется в новый массив с! Это [а]

Второй аргумент - необязательное значение, которое вы можете передать методу filter, и его можно использовать как this, когда будет выполнен ваш обратный вызов (проверьте ссылку, о которой я упомянул в начале около filter). Вы передаете туда пустой объект. Когда вы используете ключевое слово this в своем обратном вызове, обратитесь к этому объекту. Вот почему в первый раз, когда код получает этот метод, возвращается {}. Проверьте первую строку вывода второго фрагмента.

Я объясню вторую часть вашего вопроса, основываясь на втором фрагменте. При первом запуске у вас есть пустой объект (я говорю об этом), а первый обработанный номер равен 1. Таким образом, этот 1 не будет определен. Итак, !this[1] будет правдой. Таким образом, первая часть после ? выполнена который является присвоение

this[1] = true. 

Теперь this приобрел свой первый ключ, 1, со значением true. Кроме того, 1 будет возвращен из фильтра. То же самое происходит и с 2 и 3. Когда мы приходим к 1, то

!this[1] 

является ложным, так как this[1] верно. Так возвращается false, и 1 теперь не будет добавлен в массив, который будет возвращен после обработки всех элементов массива.

+0

- это индекс ??? –

+0

Нет, это случайный элемент вашего массива. – Christos

+0

@ManosKounelakis, пожалуйста, посмотрите на фрагмент, который я добавил, чтобы увидеть его в действии. – Christos

2

В принципе, .filter будет вызывать функцию callBack, предоставляя отдельные значения итерационного массива. Если callBack возвращает значение, которое разрешается до true, тогда это значение будет собрано, иначе это конкретное значение будет проигнорировано.

Здесь использовался второй аргумент filter. Этот второй аргумент будет использоваться в качестве контекста() при вызове callBack внутри. Таким образом, здесь, в вашем коде, передаваемый объект будет добавлен со значением массива как свойство для каждой итерации. И в последовательных итерациях код проверяет, что текущее значение доступно как property в первоначально переданном объекте. Если доступно, то этот тернарный оператор вернет false, в противном случае true.

Следовательно, уникальные значения будут возвращены из функции фильтра.

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 из каждого

+0

это [a] = true // как это добавляет значение и возвращает true? –

+0

Когда вы присваиваете значение переменной, оно возвращает присваиваемое значение. Если вы наберете 'a = 1' на консоли, вы увидите' 1'. Исключение в этом случае, когда вы объявляете var var var = 1, вернется undefined. – BrunoLM

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; 
Смежные вопросы