Почему для eval в JavaScript нужны скобки для оценки данных JSON? - PullRequest
33 голосов
/ 08 июня 2009

Я понял (трудным путем), что мне нужно добавить скобки вокруг данных JSON, например:

stuff = eval('(' + data_from_the_wire + ')');
// where data_from_the_wire was, for example {"text": "hello"}

(по крайней мере в Firefox 3).

В чем причина этого? Я ненавижу писать код, не понимая, что за этим стоит.

Ответы [ 7 ]

62 голосов
/ 08 июня 2009

eval принимает последовательность операторов Javascript. Парсер Javascript интерпретирует маркер ‘{’, встречающийся внутри оператора, как начало блока, а не начало литерала объекта.

Когда вы заключаете свой литерал в круглые скобки следующим образом: ({ data_from_the_wire }) Вы переключаете анализатор Javascript в режим анализа выражений. Маркер ‘{’ внутри выражения означает начало объявления литерала объекта и , а не блока, и, следовательно, Javascript принимает его как литерал объекта.

38 голосов
/ 08 июня 2009

Скобки вокруг data_from_the_wire фактически эквивалентны

stuff = eval('return ' + data_from_the_wire + ';');

Если бы вы использовали eval без скобок, то код был бы оценен, и если бы у вас были какие-либо именованные функции, они были бы определены, но не возвращены.

Возьмем в качестве примера возможность вызова функции так же, как она была создана:

(function() { alert('whoot'); })()

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

function() { alert('whoot'); }()

Итак, мы видим, что скобки фактически превращают код в возвращаемое выражение, а не просто в код для запуска.

11 голосов
/ 08 июня 2009

Я не уверен в причине, но я анализирую JSON, используя класс JSON из json.org . Это гораздо безопаснее, чем использовать eval.

9 голосов
/ 10 апреля 2012

В JavaScript фигурные скобки используются для создания операторов блока:

{
var foo = "bar";
var blah = "baz";
doSomething();
}

Вышеуказанные строки можно поместить внутри строки и eval использовать без проблем. Теперь рассмотрим это:

{
"foo": "bar",
"blah": "baz"
}

Из-за фигурных скобок движок JavaScript считает, что это групповое выражение, и, следовательно, синтаксическая ошибка вокруг символа :. Цитата из MDN ... JavaScript Guide ... Литералы объектов :

Вы не должны использовать литерал объекта в начале оператора. Это приведет к ошибке или не будет вести себя так, как вы ожидаете, потому что { будет интерпретироваться как начало блока.

Обходной путь обертывания литерала объекта внутри () работает, говоря движку обрабатывать его содержимое как выражение, а не как оператор блока. Так что это не работает:

({
var foo = "bar";
var blah = "baz";
doSomething(evil);
})
// parse error

Но это так:

({
"foo": "bar",
"blah": "baz"
})
// returns object
2 голосов
/ 08 июня 2009

Это происходит потому, что без круглых скобок JavaScript пытается интерпретировать {"text": ... как метку и завершается ошибкой. Попробуйте в консоли, и вы получите ошибку «недопустимая метка».

1 голос
/ 08 июня 2009

На самом деле это зависит от значения data_from_the_wire. В большинстве случаев ваш синтаксис в порядке, но строка, начинающаяся с {, анализируется как метка, а ваша неверна. Если вы заключите его в круглые скобки, это не позволит синтаксическому анализатору неправильно интерпретировать ваше выражение.

Просто проблема разбора, правда. Со строками, числами или функциями у вас не будет этой проблемы.

Одним из решений является всегда вычислять инструкции, а не выражения. Вы можете написать

eval('var stuff = {"text": "hello"}');
0 голосов
/ 08 июня 2009

Я не знаю, и я на самом деле заинтересован в ответе на этот вопрос, но я предполагаю, что без скобок данные в data_from_the_wire будут интерпретироваться как замыкание. Может быть, в скобках указана принудительная оценка, поэтому ассоциативный массив «возвращается».

Это тот тип догадок, который приводит к отрицательным голосам =).

EDIT

Дуглас Крокфорд упоминает двусмысленность синтаксиса на своем JSON сайте, но это мне не очень помогло.

...