localstorage: получить конкретное значение localstorage, которое содержит много элементов

В локальном хранилище у меня есть ключ 'results' с этими значениями:

[{"id":"item-1","href":"google.com","icon":"google.com"},
{"id":"item-2","href":"youtube.com","icon":"youtube.com"},
{"id":"item-3","href":"google.com","icon":"google.com"},
{"id":"item-4","href":"google.com","icon":"google.com"},
{"id":"item-5","href":"youtube.com","icon":"youtube.com"},
{"id":"item-6","href":"asos.com","icon":"asos.com"},
{"id":"item-7","href":"google.com","icon":"google.com"},
{"id":"item-8","href":"mcdonalds.com","icon":"mcdonalds.com"}]

Чтобы получить последний элемент, я использую это:

// this is how I parse the arrays
var result = JSON.parse(localStorage.getItem("result")); 


for(var i=0;i<result.length;i++) {
    var item = result[i];
    $('element').val(item.href);
}

Как я могу получить href для элемента 3 или для определенного идентификатора?


person jQuerybeast    schedule 11.11.2011    source источник


Ответы (3)


jQuery имеет вспомогательный фильтр для этого:

$(result).filter(function(){return this.id == "item-3";})[0]

Функция для href элемента с определенным идентификатором будет:

function getItemHrefById(json, itemId){
    return json.filter(function(testItem){return testItem.id == itemId;})[0].href;
}

И пример использования:

var href = getItemHrefById(result, "item-3");

Вы можете увидеть рабочий пример на http://jsfiddle.net/LXvLB/.

ОБНОВЛЕНИЕ

Если вы не можете прочитать элемент из локального хранилища, возможно, вы забыли вызвать JSON.stringify при установке значения:

localStorage["results"] = JSON.stringify([{"id":"item-1","href":"google.com","icon":"google.com"}, 
{"id":"item-2","href":"youtube.com","icon":"youtube.com"}, 
{"id":"item-3","href":"google.com","icon":"google.com"}, 
{"id":"item-4","href":"google.com","icon":"google.com"}, 
{"id":"item-5","href":"youtube.com","icon":"youtube.com"}, 
{"id":"item-6","href":"asos.com","icon":"asos.com"}, 
{"id":"item-7","href":"google.com","icon":"google.com"}, 
{"id":"item-8","href":"mcdonalds.com","icon":"mcdonalds.com"}])

Вам нужно преобразовать json в строку для правильной сериализации (и использовать JSON.parse для возврата JSON)

Это последний пример.

ИЗМЕНИТЬ

Как указал бесполезный код, этот метод значительно медленнее, чем встроенная функция фильтра (и пользовательский цикл, но я думаю, что введение нескольких новых строк кода для экономии 20-30 мс является излишним, если только производительность не является проблемой), поэтому я обновляю свой пример не использовать фильтр jquery. +1, пожалуйста, за его ответ на это.

Кроме того, здесь важно отметить, что если бы этот массив имел сотни вместо 8 закладок, цикл for, вероятно, был бы статистически примерно в два раза быстрее (поскольку ему не нужно перебирать остальную часть массива). Но в этом случае, вероятно, было бы неплохо поместить цикл for в функцию, которая возвращает первый найденный элемент, который удовлетворяет условию, и с прототипы его, вероятно, можно даже подключить к массиву.

person Goran Obradovic    schedule 11.11.2011
comment
Какой из них я использую где? Кажется, это не работает для меня... и это тоже не имеет смысла. getItemById не является переменной? - person jQuerybeast; 12.11.2011
comment
Метод jQuery .filter() используется для фильтрации узлов DOM, а не данных или массивов JSON. - person Useless Code; 12.11.2011
comment
@jQuerybeast извините, мой пример был ошибочным, вам нужно вызвать функцию, которую я сделал, а не getItemById, я исправил пример и добавил ссылку jsfiddle, чтобы вы могли видеть использование. - person Goran Obradovic; 12.11.2011
comment
@Useless-код из предоставленной вами ссылки: описание фильтра: уменьшите набор совпадающих элементов до тех, которые соответствуют селектору или проходят проверку функции. Набор совпавших элементов в данном случае представляет собой массив json. Ничто не мешает вам использовать его для этого. - person Goran Obradovic; 12.11.2011
comment
@GoranObradovic Спасибо. Я могу установить значения, как и вы. Значения устанавливаются с использованием localstorage, поэтому, когда я анализирую их с помощью JSON.parse(localStorage.getItem(result)); Я не получаю результатов. - person jQuerybeast; 12.11.2011
comment
Я обновил свой ответ, я считаю, что объект в вашем локальном хранилище не годится, так как вы не получаете от него правильный json. - person Goran Obradovic; 12.11.2011
comment
Спасибо за ваш ответ. Я не забыл вызвать JSOn при установке значений. Вот как я их устанавливаю: localStorage.setItem(result, JSON.stringify(result)); - person jQuerybeast; 12.11.2011
comment
Все выглядит найденным из вашего кода и моего кода, потому что вы установили var result = JSON.parse(stringInStorage); и я установил var result = JSON.parse(localStorage.getItem(result)); что то же самое. Остальной код я скопировал и вставил, и он не работает, хотя работает на вашем примере. - person jQuerybeast; 12.11.2011
comment
давайте продолжим обсуждение в чате - person Goran Obradovic; 12.11.2011
comment
@GoranObradovic Набор совпадающих элементов относится к элементам DOM, которые были сопоставлены селектором при создании объекта jQuery. jQuery будет принимать объекты, отличные от DOM, и это достаточно общая ситуация, когда вы можете использовать его для фильтрации общего массива, но на самом деле он не предназначен для фильтрации общих массивов. Несмотря на это, создание экземпляра jQuery создает много ненужных накладных расходов. Этот метод намного медленнее, чем использование пользовательского цикла, который возвращается, как только находит искомый элемент или Array.prototype.filter(). Сравнение скорости здесь: jsfiddle.net/53v3G - person Useless Code; 15.11.2011
comment
Я согласен. jQuery - более медленный метод, и я не думал о производительности в этом случае, но разница в 350 мс может быть даже больше (секунда или больше), если есть, скажем, 50 закладок. Я обновил свой ответ, +1 для вас, вы правы в этом, хотя я все еще думаю, что кроме производительности (не поймите меня неправильно, ЭТО сама по себе достаточная причина) нет причин не использовать jQuery для этого. Это плохой пример, но представьте, что у вас есть html-текст в переменной, и вам нужно проверить его перед добавлением в DOM, jQuery отлично работает (намного быстрее для реализации, чем регулярное выражение), даже если он не предназначен для этого :) - person Goran Obradovic; 15.11.2011

Использование собственного Array.filter

Если вы ориентируетесь только на современные браузеры (IE9+ или последнюю версию любого другого основного браузера ) вы можете использовать метод массива JavaScript 1.6 filter.

var testItem,
    data = [{"id":"item-1","href":"google.com","icon":"google.com"},
{"id":"item-2","href":"youtube.com","icon":"youtube.com"},
{"id":"item-3","href":"google.com","icon":"google.com"},
{"id":"item-4","href":"google.com","icon":"google.com"},
{"id":"item-5","href":"youtube.com","icon":"youtube.com"},
{"id":"item-6","href":"asos.com","icon":"asos.com"},
{"id":"item-7","href":"google.com","icon":"google.com"},
{"id":"item-8","href":"mcdonalds.com","icon":"mcdonalds.com"}];

function getItemById(data, id) {
    // filter array down to only the item that has the id
    // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
    var ret = data.filter(function (item) {
        return item.id === id;
    });

    // Return the first item from the filtered array   
    // returns undefined if item was not found
    return ret[0];
}


testItem = getItemById(data, 'item-3');

Рабочий пример

Ручной цикл по данным

Если вы не можете использовать фильтр, вы, вероятно, застряли только с использованием цикла:

var testItem,
    data = [{"id":"item-1","href":"google.com","icon":"google.com"},
{"id":"item-2","href":"youtube.com","icon":"youtube.com"},
{"id":"item-3","href":"google.com","icon":"google.com"},
{"id":"item-4","href":"google.com","icon":"google.com"},
{"id":"item-5","href":"youtube.com","icon":"youtube.com"},
{"id":"item-6","href":"asos.com","icon":"asos.com"},
{"id":"item-7","href":"google.com","icon":"google.com"},
{"id":"item-8","href":"mcdonalds.com","icon":"mcdonalds.com"}];

function getItemById(data, id) {
    var i, len;
    for (i = 0, len = data.length; i < len; i += 1) {
        if(id === data[i].id) {
            return data[i];
        }
    }

    return undefined;
}

testItem = getItemById(data, 'item-3');

Рабочий пример

Несмотря на то, что перебор с помощью цикла может показаться менее элегантным, чем использование Array.filter, оказывается, что в большинстве случаев цикл работает быстрее чем Array.filter.

Рефакторинг объекта вместо массива

Лучшим решением, предполагая, что id каждого из ваших элементов уникален, будет рефакторинг способа хранения данных. Вместо массива объектов используйте объект, который использует id в качестве ключа для хранения объекта, содержащего значения ключа/свойства href и icon.

var data = {
    "item-1": {"href": "google.com", "icon": "google.com"},
    "item-2": {"href": "youtube.com", "icon": "youtube.com"},
    "item-3": {"href": "google.com", "icon": "google.com"},
    "item-4": {"href": "google.com", "icon": "google.com"},
    "item-5": {"href": "youtube.com", "icon": "youtube.com"},
    "item-6": {"href": "asos.com", "icon": "asos.com"},
    "item-7": {"href": "google.com", "icon": "google.com"},
    "item-8": {"href": "mcdonalds.com", "icon": "mcdonalds.com"}
};

Это сделало бы доступ к элементам еще проще и быстрее:

var data = JSON.parse(localStorage.getItem("result")); 
data["item-3"].href;
person Useless Code    schedule 12.11.2011
comment
Привет и спасибо. В моем случае я устанавливаю testItem как JSON.parse(localStorage.getItem(result)). Когда я это делаю, все результаты не определены. - person jQuerybeast; 12.11.2011
comment
Я действительно не знаю, как это объяснить, но я не устанавливаю все значения, как вы. Я разбираю их, а затем получаю неопределенность в обоих примерах. - person jQuerybeast; 12.11.2011
comment
@jQuerybeast В исходном примере была просто установка тестовых данных, а затем доступ к ним через закрытие, я изменил его, чтобы вместо этого использовать его в качестве параметра. Затем вы можете вызвать его, передав ему данные: testItem = getItemById(JSON.parse(localStorage.getItem("result")), 'item-3');. Если вам нужно получить более одного элемента, вам, вероятно, следует присвоить результаты JSON.parse(localStorage.getItem("result")) переменной, а не вызывать ее как встроенную. - person Useless Code; 12.11.2011
comment
@Hugolpz, ты слишком часто меняешь ответы. Вы меняете код, вы меняете смысл. Я, например, никогда не одобрю эти правки. Не буду спорить с вами по этому поводу, но мой личный совет — не делайте таких изменений. Не стесняйтесь исправлять грамматику и орфографию, но позвольте автору сообщения исправить код или изменить имена переменных или что-то еще. Не делай этого сам. - person Shadow Wizard Wearing Mask V2; 10.02.2013
comment
@ShadowWizard: веб 2.0. Если это разъяснение, лучшее разъяснение, лучшая иерархия-сегментация, лучшая читабельность: давайте просто сделаем это. - person Hugolpz; 10.02.2013
comment
@Hugolpz Я сказал свою часть. Многие из ваших предложений были отклонены, и вскоре вам будет запрещено предлагать дальнейшие изменения, если вы этого еще не сделали. Это сайт вопросов и ответов, а не Википедия. - person Shadow Wizard Wearing Mask V2; 10.02.2013
comment
@ShadowWizard: ??? вы говорите новому пользователю, что он уже может быть забанен за добросовестные правки, которые вы только что заявили как нежелательные несколько часов назад. Особенность нового пользователя, входящего в сообщество, заключается в том, что мы точно не знаем ни местных правил, ни инструментов. Обучение продолжается после отзывов. Есть кнопка редактирования, есть боковая панель, в которой говорится, что разъяснения приветствуются. Вы первый негативный отзыв, который я получаю. - person Hugolpz; 10.02.2013
comment
@Hugolpz один. Два. Три. Тот факт, что некоторые пользователи согласны с вами, не делает это правильным, поскольку вы видите, что многие пользователи отвергают ваши правки, а не только я. - person Shadow Wizard Wearing Mask V2; 10.02.2013
comment
@ShadowWizard: о... Я не знал об этих отзывах/практиках. - person Hugolpz; 10.02.2013
comment
@Hugolpz Меня тоже немного раздражали эти правки. Добавление заголовка к каждому из различных методов — это нормально, но разделение избыточных частей кода примера делает его менее понятным и трудным для понимания. Точно так же объединение заголовков «Обновление» и «Лучшее решение» в «Обновление/Лучшее решение» меняет значение. Обновление заключалось в том, что циклы работают быстрее, чем фильтры. Лучшее решение, которое я добавил, требует рефакторинга, но даже быстрее, чем циклы, объединение их под одним заголовком стирает это различие. - person Useless Code; 11.02.2013
comment
@UselessCode: я не знал, что Stackoverflow более консервативен в отношении политики редактирования, чем википедия, и смело продвигал ее, что заняло у меня время. Просто с этого момента я буду более осторожен и меньше редактирую. - person Hugolpz; 11.02.2013
comment
Итак, теперь я лучше понимаю методы локального редактирования SOF. Стоит ли удалять эти комментарии не по теме? - person Hugolpz; 12.02.2013

для метода фильтра jquery я думаю, что использование функции обратного вызова и привязка параметра поиска более элегантны и читабельны:

function filterById(id, i, obj) {
    return obj.id === id;
}

function getItemHrefById(json, itemId) {
    return $(json).filter(filterById.bind(null, itemId))[0].href;
}

обычная скрипка

(однако я предпочитаю для этого подход "для цикла"!!)

person roselan    schedule 12.11.2011