Не удается установить логические значения в LocalStorage?

113

Я заметил, что я не могу установить логические значения в localStorage?

localStorage.setItem("item1", true);
alert(localStorage.getItem("item1") + " | " + (localStorage.getItem("item1") == true));

Всегда предупреждает, true | falseкогда я пытаюсь проверить localStorage.getItem("item1") == "true"это предупреждение true ... Как я могу установить элемент в localStorageзначение true?

Даже если это строка, я думал только ===проверить тип?

Так

alert("true" == true); // should be true? 
Jiew Meng
источник

Ответы:

69

Реализация хранилища в Firefox может хранить только строки, но сентябре 2009 года W3C изменил черновик, чтобы принимать любые данные.Реализация (все еще) еще не догнала( см. Правка ниже ).

Итак, в вашем случае логическое значение преобразуется в строку.

Что касается того "true" != true, почему , как написано в описании Equal ( ==) в MDC *:

Если два операнда не одного типа, JavaScript преобразует операнды, а затем применяет строгое сравнение. Если один из операндов является числом или логическим значением, операнды по возможности преобразуются в числа ; иначе, если один из операндов является строкой, другой операнд преобразуется в строку, если это возможно.

Обратите внимание, что строка преобразуется в число вместо логического . Поскольку "true"преобразовано в число NaN, оно не будет равно ничему, поэтомуfalse возвращается.

(*: Фактический стандарт см. В ECMA-262 §11.9.3 «Абстрактный алгоритм сравнения равенства»)


Edit:setItem интерфейс был вернулся принимать строки только на сентябрь 1 - го проекта 2011 года в соответствии с поведением существующих реализаций, так как ни один из поставщиков не заинтересованы в поддержке хранящих не-строк. Подробнее см. Https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 .

kennytm
источник
2
Если любой из операндов является числом или логическим значением, операнды преобразуются в числа, если это возможно - я этого совершенно не осознавал. Я думал, что если бы одна была строкой, другая была преобразована в строку. Ура (+1).
Andy E
2
@ Энди, прочтите полезные заметки по этой теме.
CMS
91

На данный момент все реализации Safari , WebKit, Chrome, Firefox и IE соответствуют старой версии стандарта WebStorage, где значение элементов хранилища может быть только строкой.

Можно было бы использовать JSON parseи stringifyметод для сериализации и десериализации данных, как я предлагал некоторое время назад в другом вопросе , например:

var value = "true";
JSON.parse(value) === true; // true
CMS
источник
4
Это, очевидно, сломается, если переданная строка valueнедействительна JSON (например JSON.parse("a random string"))
Адонис К. Какулидис
3
Верно @AdonisK. Но если он использует JSON.stringify при установке всех значений, он может снять с себя ответственность за вывод действительного JSON в библиотеку. И это очень стабильная библиотека.
Colt McCormack
12

Мои решения:

function tytPreGetBool(pre) {
    return localStorage.getItem(pre) === 'true';
}
Tyttoot
источник
2
@koppor Может быть, потому что, если getItem когда-либо вернет логическое значение, этот метод даст ложные результаты, поскольку true == 'true'есть false.
jox 05
8
... или просто localStorage.getItem(pre)==='true'без остального
phil294
1
@koppor, почему это отклонено? потому что самодовольные укладчики переполнены, буквально :)
Ayyash
1
"? true: false" не требуется, поскольку localStorage.getItem (pre) == 'true' уже дает логический результат
FelipeDrumond
6

Это связано с ответом CMS.

Вот небольшая функция, которую я использовал для обработки части синтаксического анализа этой проблемы (функция будет продолжать делать правильную вещь после того, как реализации браузера догонят спецификацию, поэтому не нужно помнить об изменении кода позже):

function parse(type) {
   return typeof type == 'string' ? JSON.parse(type) : type;
}
старший
источник
1
Разве это не лишнее по сравнению с JSON.parse? JSON.parse ("true") и JSON.parse (true) уже оба возвращают true, поэтому все равно будут поступать правильно после того, как браузеры реализуют логическое localstorage
bscan
3

Используйте store.js :

localStorage.setItem('isUser', true)
localStorage.getItem('isUser') === "true" //true
npm i -D store

store.get('isUser')  //true
фронтенд-инженер
источник
4
Но действительно ли необходимо включать целую библиотеку только для этой простой задачи преобразования строки в логическое значение?
jayqui
1

Я не уверен, может ли LocalStorage сохранять логические значения, но могу сказать вам, что когда вы это сделаете, alert("true" == true);он никогда не будет оценивать значение true, потому что вы неявно сравниваете строку с логическим значением. Вот почему для установки логических значений вы используете trueвместо "true".

Римский
источник
1
А как насчет предупреждения ("1" == 1)? Javascript - странный (и непоследовательный) зверь.
Спендер
@spender: это потому, что правый операнд приводится к строке для сравнения. "1" === 1на самом деле вернет false.
Andy E
@Kenny: whoops facepalm , спасибо за исправление :-) Я запутался из-за того, как логические значения приводятся к строкам.
Andy E
1

evalв некоторых случаях может использоваться с осторожностью .

console.log(eval("true") === true) //true
тупик
источник
Избегайте, evalтак как это может быть небезопасно. Предпочитаю JSON.parse("true").
Фред
1

Обычно я просто сохраняю значение в LocalStore как логическое значение, а затем извлекаю его методом синтаксического анализа, чтобы быть уверенным во всех браузерах. Мой метод ниже настроен для моей бизнес-логики. Иногда я могу хранить что-то как `` нет '' и мне все равно нужно falseвзамен

function toBoolean(str) {
    if (typeof str === 'undefined' || str === null) {
        return false;
    } else if (typeof str === 'string') {           
        switch (str.toLowerCase()) {
        case 'false':
        case 'no':
        case '0':
        case "":
            return false;
        default:
            return true;
        }
    } else if (typeof str === 'number') {
        return str !== 0
    }
    else {return true;}
}
JohnPan
источник