Pull to refresh

Comments 74

Вопрос не нов — она не нужна. Да и мешает она браузерам оптимизировать код:


Кто не понял что хотел сказать TheShock —
eval на всякий случай заявляет о том что он будет использовать все переменные до которых в принципе может дотянуться.
Потому что хрен знает какие из доступных он будет использовать.
Как говорится, нельзя, но если очень-очень хочется, то можно.
Я удручён количеством хабрахабровцев, не имеющих представления о JSON.parse().
А если волею хаоса с сервера приходит не объект в JSON, а исполняемый код?
да уже спас, новые браузеры его поддерживают, для старых небольшая библиотечка которая его реализует в 1кб помоему.
Сложно себе представляю, как с сервера может прийти, даже, волею хаоса, javascript код (Если, конечно, сам developer этого не задумывал).
Если быть объективным, то в каком-то старом Google Maps Api мне приходил невалидный JSON (как в обычном JS — без кавычек на ключах)
Послать лучи поноса разрабам сервера и таки заюзать eval про себя матерясь и обещая его заменить на JSON::parse?
Сам eval никогда не использую, не было необходимости, но допускаю, что может возникнуть гипотетическая ситуация, в которой eval будет наилучшим решением. Поэтому второй ответ.
А вот, к примеру, как без eval динамически создать именованную функцию? С eval это просто.
var F = eval("1 && function " + o.type + "(){}");

Как уже неоднократно говорилось, грабли это не только инструмент самоубийства, но и полезное сельхозорудие.
Вот пример кода. Обратите внимание, как объекты назваются в консоли.

Словами — если в приложении предполагается создавать много объектов, то разумно использовать для этого специальный инструмент. Обычно используют функцию create Крокфорда. Но если ее использовать так, как есть, то в консоли объекты будут называться «Object». Нам же хотелось бы, чтобы они назывались — «Man», «Woman», «Point» и т.д. С помощью eval этого легко можно достичь. При этом нет ни проблем производительности (так как количество вызовов равно количеству типов), ни проблем безопасности (так как мы контролируем передающийся код).

Если Вы знаете для этого более подходящую методику, я с радостью ее перениму.
Да, и конечно, для instanceof это большое подспорье.
Это был заскок. Конечно же, instanceof и для метода Крокфорда действует, если передавать нужный прототип.
Это аргумент, согласен. Мы решили это дописыванием в свойства класса Constructor: 'Name'. Всё-равно имя функции не может содержать, скажем, точку, которая нужна для пространства имён.
В любом случае я бы подобный код с eval, который на практике нужен только для отладки на production выключал бы и использовал чистый код. Мало ли, как этот evil может помешать браузерам оптимизировать ;)
Кстати, да, для продакшена это все не нужно и обертка убирается.
Вопрос в том, как это легко и изящно убрать в продакшне? =)
мы используем специальный комментарий, выглядит вот так
    var F = /** @cut */ new Function('constructor', 'return {"' + o.type + '": ' +
      function(){
        constructor.apply(this, arguments);
      }
    /** @cut */ + '}["' + o.type + '"]')(constructor);

Функция создания классов весьма специфичная, к ее коду не приходится часто обращаться, поэтому здесь это допустимо и оправдано. В остальном коде такой подход, конечно, моветон.
Ещё меня напрягает, что в дебагере это дополнительный шаг, когда мы хотим отладить конструирование объекта. Не критично, конечно, но факт
debugger;
new F();
Это совсем не критично, особенно при длинном наследовании (когда цепочка классов длинная). К тому же debugger обычно ставится в определенный constructor, для отладки.
Ну и это оправданная мера, ибо что лучше видеть в консоли:
[new Man, new Woman];
// так?
[Man, Woman]
// или так?
[Object, Object]

Для меня выбор очевиден :)
Спасибо. Интересно. Нужно обдумать.
Создать в глобальном пространстве имён функцию с заданным именем и пустым телом?

Да пожалуйста:

function createEmptyFunction(cefName){
   // для браузера:
   window[cefName] = function(){}

   // или для Node.js:
   global[cefName] = function(){}
}

// вызывать как-нибудь так:
createEmptyFunction( o.type );
Да, виноват. Не указал, что в локальном контексте.
Хотя, с другой стороны, о чем-то наверное var F говорило в коде. Нет?
А никак сделать хеш-объект и туда совать функции?
var obj = {};
function create(name){
 obj[name] = function(){}
}
UFO just landed and posted this here
Для подобного, использую такую магию:
    var F = new Function('constructor', 'return {"' + o.type + '": ' +
      function(){
        constructor.apply(this, arguments);
      }
    + '}["' + o.type + '"]')(constructor);

Этот способ так же позволяет давать названия с точкой (да и вообще любое название), что в вашем варианте не получится. Например:
var Man = create({
    type: 'Human.Man',
    ...
});

Работает в webkit, FF, IE (как минимум в 9)
Да, пожалуй, так лучше.

А какие-то проблемы встречали с таким решением?
С точки зрения робастости, за полтора года никаких. В худшем случае в консоли будет не то что ожидалось (но пока такого не было).
В продакшене эта обертка убирается, так как там не важно какое имя будет у функций — хотя это не обязательно.
Единственное, что нужно помнить:
1. Функция внутри обертки не имеет доступ к общей области видимости. Все необходимые переменные нужно пробрасывать внутрь, как в примере пробрасывается constructor.
2. При упаковке (например, google closure) переменные внутри (как в примере — constructor) будут переименованы в короткие имена, при этом имена параметров останутся прежними. То есть будет что-то вроде:
    var F = new Function('constructor', 'return {"' + o.type + '": ' +
      function(){
        a.apply(this, arguments);
      }
    + '}["' + o.type + '"]')(a);

Поэтому либо обертку нужно убирать при упаковке, либо внутренним переменным давать имена, которые не встречаются в общей области видимости, что не позволит упаковщику переименовать переменную. Например, так:
    var F = new Function('constructor_', 'return {"' + o.type + '": ' +
      function(){
        constructor_.apply(this, arguments);
      }
    + '}["' + o.type + '"]')(constructor);
Спасибо, что поделились этим заклинанием.
В ASP.NET WebForms иногда очень спасает, например: eval($('a.some-ling-button').attr('href').replace(....));
Господа, объясните почему минусуем? Если это «тупое» решение, буду рад узнать об «умном», действительно интересно.
Буду рад сказать вам умное решение, если вы озвучите задачу.
Вы знаете о LinkButtons в ASP.NET WebForms?
Бывают ситуации, когда нужно нажать кнопку программно.
Код кнопки на клиенте представляет собой что-то такое:
...
$('...').click() — срабатывает не всегда, так что абсолютно кроссбраузерный способ может быть и есть, но мне не известен.
пардон, код кнопки был съеден хабрапарсером:
<а href=«javascript:__doPostBack('ctl00$bodyContent$dxPagerTop','PN2');»>...</а>
Варианты:
1) window.location = $('a.some-ling-button').attr('href')
2) Не храните в htef, храните в onclick. $('...').click() будет срабатывать.
3) Вообще не хранить код в html.
Сразу видно, что вы не знаете о чем говорите :) ASP.NET WebForms не дает выбирать где хранить их любимый вызов __doPostBack :)
Можеть вместо того, чтобы обсуждать меня, скажете, решена ли ваша проблема без использования eval(), или первый способ вам тоже чем-то не подходит?
Это не моя проблема, это довольно известный костыль, его никто не решил. Поверьте мне. А вы говорите со мной как со студентом :)
Вы не привели никаких доводов.

> Поверьте мне.
Разве это вопрос веры?
У Вас много времени? Ну тогда проверьте. У меня мало времени, а обсуждение безрезультативно затянулось.
> Если это «тупое» решение, буду рад узнать об «умном»,
> буду рад узнать
Помоему вы начинаете троллить. Вы не в теме, не обижайтесь, но у вас нет соответствующих знаний. Ваши предложенные варианты совсем не в тему.
Вы так уверенно об этом заявляете, но по прежнему отказываетесь рассказать, почему.
Создайте проект в ASP.NET, добавьте грид на страницу, сделайте в ячейке LinkButton, забиндете какую-нибудь коллекцию, а теперь попробуйте сэмулировать нажатие на ссылку программно из JavaScript.
Это все замечательно, но к делу не относится. Есть ссылка, есть код в href=«javascript:». Этот код можно выполнить так же, как он выполняется, когда пользователь нажимает на ссылку — передать её в window.location.

Вы на 100% уверены, что это не сработает. Почему?
Это кроссбраузерное решение?
Да, вы абсолютно правы, в данный момент это решение для меня работает. Буду пользоваться, спасибо :)
Не могу не заметить, что я также успел побывать абсолютно неправым, что решению вы были как рады, так и не было на это времени.

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

И главное повесить try, если он обрабатывает все ошибки, кроме синтаксических.
Иногда, очень редко, я её использую как временное решение, чтобы не отвлекаться от общей задачи и не искать сразу подходящий вариант. Затем во время рефакторинга, когда тесты — зелёные, начинаю от неё избавляться.
Кто-нибудь вспомнил, что jQuery использует почти eval при недоступности нативной функции JSON.parse?
Присоединяюсь. Часто разработчик не знает, что в используемых библиотеках или фреймворках eval таки используется.
В ExtJS он используется в декодировании JSON, если операция нативно не поддерживается браузером, а так же для генерации аксессоров для Ext.data.Record (правда, последнее справедливо для третьей версии).
UFO just landed and posted this here
Потому, что наверное здесь считают, что обфуксация не нужна, вы что ли скрипты за деньги продаете или у вас там зашифрован алгоритм по созданию Скайнета?
Ну сжатие для уменьшения размера через eval тоже имеет место быть
и прощай оптимизации? Круто же!
А скрипт подключить через <script src=«data://Распакованный_код_в_base64»/> нельзя? По идее должен грузиться как обычный скрипт, а не как eval, а потому на оптимизации не повлияет.
UFO just landed and posted this here
Подводя итоги, можно сделать вывод, что иногда без функции eval просто не обойтись. И большинство принимают правильное решение: её можно использовать, но чем меньше — тем лучше.
От себя хочется добавить ярым противникам eval:
Неважно, как появился код: загружен сторонний скрипт, с помощью Function, с помощью eval — все равно он может быть потенциально опасным. А так называемое зло eval (потенциальный доступ к переменным, медленность работы) преувеличено, потому что всё зависит только от степени понимания программистом тонкостей языка. Если ты быдлокодер, то и без eval наделаешь уязвимостей.
Подводя итоги, можно сделать вывод, что иногда без функции eval просто не обойтись

Странные итоги. Как раз подведя итоги можно сказать, что без неё можно запросто обойтись, просто иногда ею пользуются.
Объясните, возможно, я в чем-то не прав, но считаю, что юзать eval() лучше при запросе к своему серверу, при уверенности, что он отдаст только правильную информацию.

Например, при авторизации или добавлении записи куда-то я делаю запрос к серверу и от отдает мне JSON массив с результатом либо в таком виде:

#res['status']='OK';
#res['code']='200';
#res['title']='Ваше сообщение успешно добавлено';
#res['message']='2547854';

либо в таком:

#res['status']='Error';
#res['code']='012';
#res['title']='Сообщение о какой-либо ошибке';

Все. Других вариантов я не жду. Считаю, что в даннов случае eval() выручит без вопросов и угроз от него можно не ждать.

Но уже при запросе к внешнему ресурсу, даже такому надежному как Google или YouTube лучше делать промежуточный запрос через свой сервер, где уже средствами PHP делать запрос к внешнему серверу, обрабатывать результаты, фильтровать, упаковывать их как надо и отдавать своему JS.

Накрайняк в JS можно максимально обработать спецсимволы посkt распаковки JSON от сервера.

Возможно, я не прав, поправьте.
Кстати ВК юзает вот эту фенечку

var parseJSON = (window.JSON && JSON.parse)? function (obj) {
try { return JSON.parse(obj); } catch (e) {
return eval('('+obj+')');
}
}: function(obj) {
return eval('('+obj+')');
}

UFO just landed and posted this here
Sign up to leave a comment.

Articles