2016-03-30 2 views
2

Итак, я подумал, что было бы интересно написать несколько методов Array, чтобы помочь в сортировке и группировании объектов. Вот мой код. Извините log s, это заставляет меня бананы. Вы можете запустить этот код на JSBin, here.Array.find() получает правильное значение, но возвращает неверный

/** 
* uniquePush method - conditionally add an object to an array 
* 
* Only adds an object if it is not already present on this array. 
* Doesn't do a deep comparison. 
* 
* @param {Object} newElement - the element to check for before pushing 
* @returns {Array} the array, modified if nescessary 
*/ 
Array.prototype.uniquePush = function (newElement) { 
    console.dir(this); 
    var findCount = 0; 

    function findNewElement(element) { 
    console.log("findCount: " + (++findCount)); 
    console.log("Element: " + element); 
    console.log("newElement: " + newElement); 
    var found = (element === newElement); 
    console.log("findNewElement -> " + found); 
    return found; 
    } 

    var foundNewElement = this.find(findNewElement); 
    console.log("this.find(findNewElement): " + foundNewElement) 
    if (foundNewElement) { 
    // Found it. Don't add it. 
    console.log("Declined to add \'" + newElement + "\' to array"); 
    } else { 
    // Didn't find it, go ahead and add it 
    console.log("Adding \'" + newElement + "\' to array"); 
    } 

    console.log("---------------------------------"); 
    return (foundNewElement ? this : this.push(newElement)); 
} 

/** 
* groupBy method - groups an array of objects by property value 
* 
* Returned Array will look like: 
* [ 
* [{prop: "propValue", ...}, {prop: "propValue", ...}], 
* [{prop: "anotherValue", ...}, {prop: "anotherValue", ...}], 
* ... 
* [{prop: "nValue", ...}, {prop: "nValue", ...}] 
* ] 
* 
* @param {String} prop - the property to group by 
* @returns {Array} an Array containing the grouped arrays 
*/ 
Array.prototype.groupBy = function (prop) { 
    // Gather all the possible property values 
    var propValues = []; 
    var entries = this.entries(); 

    var entryValue; 
    while (entryValue = entries.next().value) { 
    propValues.uniquePush(entryValue[1][prop]); 
    } 

    var result = []; 
    for (var i = 0; i < propValues.length; i += 1) { 
    var innerResult = []; 
    this.forEach(function(element) { 
     if (element[prop] === this.propValue) { 
     this.result.push(element); 
     } 
    }, { 
     propValue: propValues[i], 
     result: innerResult 
    }); 
    result.push(innerResult); 
    } 
    return result; 
}; 

var PRODUCTS = [ 
    {category: 'Sporting Goods', price: '$29.99', stocked: true, name: 'Football'}, 
    {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'}, 
    {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'}, 
    {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'}, 
    {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'}, 
    {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'} 
]; 

var groupedByCategory = PRODUCTS.groupBy("category"); 
console.dir(groupedByCategory); 
var groupedByStocked = PRODUCTS.groupBy("stocked"); 
console.dir(groupedByStocked); 

Этот код в основном работает нормально, но я нахожу, что он имеет проблемы с массивами булевых значений. В частности, метод uniquePush() использует метод Array.find(), чтобы определить, присутствует ли данный newElement в массиве this.

Однако похоже, что он возвращает неправильное значение. Когда я запускаю его на "stocked", например, я получаю это:

<edited for brevity> 

[true, false] 
"findCount: 1" 
"Element: true" 
"newElement: true" 
"findNewElement -> true" 
"foundNewElement: true" 
"---------------------------------" 
"Declined to add true to array" 
[true, false] 
"findCount: 1" 
"Element: true" 
"newElement: false" 
"findNewElement -> false" 
"findCount: 2" 
"Element: false" 
"newElement: false" 
"findNewElement -> true" 
"foundNewElement: false" 
"---------------------------------" 
"Adding false to array" 
[true, false, false] 

Как вы можете видеть, в конце концов, findNewElement оценивается в true Тем не менее Array.find() возвращается false. Может кто-нибудь объяснить мне, почему это происходит?

+0

IndexOf() следует использовать, если вы ищете целые элементы. – dandavis

ответ

1

Array.find возвращает undefined, если ничего не найдено.

var foundNewElement = this.find(findNewElement); 
    if (foundNewElement) ... 

Если он считает, что «ложь» эта проверка не удалась. Использовать if (typeof(foundElement)!='undefined')

+0

Если 'newElement === undefined', вы не будете знать, нашли ли вы это или нет. – Oriol

+0

Ну, я не думаю, что вы можете найти что-то неопределенное, логически говоря :) Я подумал об этом и отклонил его как глупо. И я немного старая школа, поэтому '=== undefined', в то время как она работает в наши дни, она не использовалась для исторической работы, когда вы могли сделать undefined = 2 в Internet Explorer. –

1

Код - это способ перепутаться. Вот простое решение, которое вам может понравиться.

Array.prototype.uniquePush = function (newElement) { 
    return this.indexOf(newElement) !== -1 ? this : this.push(newElement); 
} 

https://jsbin.com/nexuboqavo/edit?html,output

+0

Будет ли это работать с неиндексированными элементами массива? Как сказать 'array [" some string "]'? – deathgaze

+0

No :) Это простой массив. Если вы хотите поддерживать объекты, вы также можете легко сделать это с помощью Object.ключи (вернет массив ключей) ... – Aleksandrenko

1

Я думаю, вы поняли [].find. Он используется для извлечения первого значения, которое удовлетворяет некоторому условию, а не для проверки того, принадлежит ли значение массиву.

Если вы хотите сделать последний, вы можете использовать

  • ES5 [].indexOf. Сравнивает с алгоритмом Strict Equality.

    myArray.indexOf(value) > -1 
    
  • ES6 [].findIndex. Вы можете предоставить свою собственную функцию компаратора.

    myArray.findIndex(item => item === value) > -1 
    
  • ES7 [].includes. Сравнивает с алгоритмом SameValueZero.

    myArray.includes(value) 
    
Смежные вопросы