Eval - это зло, но разве оно испорчено?
Если я запустил это:
eval('{ear: {"<=": 6}}');
Я получаю сообщение об ошибке:
Uncaught SyntaxError: Неожиданный токен:
Создайте объект вручную:
var foo = {};
foo.ear = {};
foo.ear["<="] = 6;
Теперь, следующий код:
JSON.stringify(foo)
Возвращает следующую строку:
'{ "уха": { "< =": 6}}'
Та же строка, что и я, с которой я начал (за исключением белых символов, но это не имеет значения), поэтому eval(JSON.stringify(foo))
возвращает одно и то же сообщение об ошибке синтаксического сообщения. Однако:
$.parseJSON(JSON.stringify(foo))
выполняется правильно. В чем причина этого?
EDIT:
Как указывали nnnnnn и Рон Дадон, исходная строка и результат stringify
различны. Однако, как я указал в вопросе, даже результат stringify
, используемый в качестве ввода для eval
, приведет к сообщению синтаксической ошибки.
EDIT2:
На основе ответов и экспериментов эта функция интересна:
function evalJSON(text) {
return eval("(" + text + ")");
}
Ответы
Ответ 1
Основные {}
анализируются как заявка блока.
попробуйте скопировать в скобки:
eval('({ear: {"<=": 6}})');
В javascript {}
может быть проанализирован как блок или объект
примеры:
//object
var user = {
name: "John",
age: "32"
};
//block
{
let a = 5;
console.log(a);
}
//object:
var a = {};
console.log({});
return {};
({});
//block:
function(){}
for(k in o){}
{}
Ответ 2
Это не испорчено. Чтобы понять, что происходит, вам нужно понять, какие выражения видны (слева направо) парсером.
Простой способ войти в него - это играть с Javascript AST Visualizer
-
Вы получите то же самое исключение с гораздо более простым {"b":4}
. Он анализировался как "b":4
внутри block. Это недействительный javascript. Нет дерева АСТ для вас...
Однако из-за исключения внутри оператора {}
. Это a BlockStatement
. AST tree: ![Дерево AST для {}]()
-
Аналогичный {b:4}
будет пониматься как b:4
, действительный оператор js - a b
label для 4
... Это проанализировано как ![Дерево AST для {b: 4}]()
-
Наконец, a ({b:4})
будет пониматься как объявление объекта с свойством b
, равным 4
. Это проанализировано как ![Дерево AST для ({b: 4})]()
ECMAScript 2015
Вкл Блоки:
Блок: {StatementList}
В eval:
Eval создает новый Realm
, который анализируется (здесь несколько шагов) в виде последовательности Statement
(a StatementList
), которая, в свою очередь, this раздел имеет BlockStatement
как первый вариант. Этот должен начинаться с {
(см. Выше), поэтому, если вы оберните его скобкой (({})
), то не может быть BlockStatement
... Но если он соответствует BlockStatement
, то должен быть BlockStatement
.
Примечание в разделе Выражения:
ExpressionStatement не может начинаться с U + 007B (LEFT CURLY BRACKET), потому что это может сделать его неоднозначным с блоком
Ответ 3
Должны быть оценены литеральные обозначения объектов. Это происходит, когда вы назначаете переменную:
var a = {ear: {"<=": 6}};
или когда вы помещаете круглые скобки вокруг него, анонимный объект:
({ear: {"<=": 6}});
В противном случае фигурные скобки обрабатываются как маркеры блоков. В вашем случае это означает, что {ear:...}
- это определение метки, метка называется ухом. Следующий блок {"<=": 6}
дает вам синтаксическую ошибку, потому что "<=": 6
является недопустимым синтаксисом.
То же самое относится, если вы помещаете это в оператор eval
.