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




Как говорится, нельзя, но если очень-очень хочется, то можно.
Я удручён количеством хабрахабровцев, не имеющих представления о JSON.parse().
Всего 6? (На момент написания комментария)
А если волею хаоса с сервера приходит не объект в JSON, а исполняемый код?
Насколько я понимаю, JSON.parse() от этого и спасает.
Сложно себе представляю, как с сервера может прийти, даже, волею хаоса, javascript код (Если, конечно, сам developer этого не задумывал).
Послать лучи поноса разрабам сервера и таки заюзать eval про себя матерясь и обещая его заменить на JSON::parse?
Сам eval никогда не использую, не было необходимости, но допускаю, что может возникнуть гипотетическая ситуация, в которой eval будет наилучшим решением. Поэтому второй ответ.
А вот, к примеру, как без
Как уже неоднократно говорилось, грабли это не только инструмент самоубийства, но и полезное сельхозорудие.
eval
динамически создать именованную функцию? С eval
это просто.var F = eval("1 && function " + o.type + "(){}");
Как уже неоднократно говорилось, грабли это не только инструмент самоубийства, но и полезное сельхозорудие.
А зачем?
Вот пример кода. Обратите внимание, как объекты назваются в консоли.
Словами — если в приложении предполагается создавать много объектов, то разумно использовать для этого специальный инструмент. Обычно используют функцию
Если Вы знаете для этого более подходящую методику, я с радостью ее перениму.
Словами — если в приложении предполагается создавать много объектов, то разумно использовать для этого специальный инструмент. Обычно используют функцию
create
Крокфорда. Но если ее использовать так, как есть, то в консоли объекты будут называться «Object». Нам же хотелось бы, чтобы они назывались — «Man», «Woman», «Point» и т.д. С помощью eval
этого легко можно достичь. При этом нет ни проблем производительности (так как количество вызовов равно количеству типов), ни проблем безопасности (так как мы контролируем передающийся код).Если Вы знаете для этого более подходящую методику, я с радостью ее перениму.
Да, и конечно, для
instanceof
это большое подспорье.Это аргумент, согласен. Мы решили это дописыванием в свойства класса
В любом случае я бы подобный код с eval, который на практике нужен только для отладки на production выключал бы и использовал чистый код. Мало ли, как этот evil может помешать браузерам оптимизировать ;)
Constructor: 'Name'
. Всё-равно имя функции не может содержать, скажем, точку, которая нужна для пространства имён.В любом случае я бы подобный код с eval, который на практике нужен только для отладки на production выключал бы и использовал чистый код. Мало ли, как этот evil может помешать браузерам оптимизировать ;)
Можно и с точкой и без eval, см мой комментарий
Кстати, да, для продакшена это все не нужно и обертка убирается.
Вопрос в том, как это легко и изящно убрать в продакшне? =)
мы используем специальный комментарий, выглядит вот так
Функция создания классов весьма специфичная, к ее коду не приходится часто обращаться, поэтому здесь это допустимо и оправдано. В остальном коде такой подход, конечно, моветон.
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 );
Для подобного, использую такую магию:
Этот способ так же позволяет давать названия с точкой (да и вообще любое название), что в вашем варианте не получится. Например:
Работает в webkit, FF, IE (как минимум в 9)
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) будут переименованы в короткие имена, при этом имена параметров останутся прежними. То есть будет что-то вроде:
Поэтому либо обертку нужно убирать при упаковке, либо внутренним переменным давать имена, которые не встречаются в общей области видимости, что не позволит упаковщику переименовать переменную. Например, так:
В продакшене эта обертка убирается, так как там не важно какое имя будет у функций — хотя это не обязательно.
Единственное, что нужно помнить:
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() — срабатывает не всегда, так что абсолютно кроссбраузерный способ может быть и есть, но мне не известен.
Бывают ситуации, когда нужно нажать кнопку программно.
Код кнопки на клиенте представляет собой что-то такое:
...
$('...').click() — срабатывает не всегда, так что абсолютно кроссбраузерный способ может быть и есть, но мне не известен.
пардон, код кнопки был съеден хабрапарсером:
<а href=«javascript:__doPostBack('ctl00$bodyContent$dxPagerTop','PN2');»>...</а>
<а href=«javascript:__doPostBack('ctl00$bodyContent$dxPagerTop','PN2');»>...</а>
Варианты:
1) window.location = $('a.some-ling-button').attr('href')
2) Не храните в htef, храните в onclick. $('...').click() будет срабатывать.
3) Вообще не хранить код в html.
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% уверены, что это не сработает. Почему?
Вы на 100% уверены, что это не сработает. Почему?
Чтобы понять о чем я, можно прочесть www.xefteri.com/articles/show.cfm?id=18
Редко, только в самых крайних случая, только когда нету вообще нету никаких вариантов кроме eval.
Я такие функции в любых языках (интерпретируемых) считаю опасными и частично не предсказуемыми, по этому только если как кровь с носа надо и других вариантов нету.
И главное повесить try, если он обрабатывает все ошибки, кроме синтаксических.
Я такие функции в любых языках (интерпретируемых) считаю опасными и частично не предсказуемыми, по этому только если как кровь с носа надо и других вариантов нету.
И главное повесить try, если он обрабатывает все ошибки, кроме синтаксических.
Иногда, очень редко, я её использую как временное решение, чтобы не отвлекаться от общей задачи и не искать сразу подходящий вариант. Затем во время рефакторинга, когда тесты — зелёные, начинаю от неё избавляться.
Кто-нибудь вспомнил, что jQuery использует почти eval при недоступности нативной функции JSON.parse?
Присоединяюсь. Часто разработчик не знает, что в используемых библиотеках или фреймворках eval таки используется.
В ExtJS он используется в декодировании JSON, если операция нативно не поддерживается браузером, а так же для генерации аксессоров для Ext.data.Record (правда, последнее справедливо для третьей версии).
В ExtJS он используется в декодировании JSON, если операция нативно не поддерживается браузером, а так же для генерации аксессоров для Ext.data.Record (правда, последнее справедливо для третьей версии).
Потому, что наверное здесь считают, что обфуксация не нужна, вы что ли скрипты за деньги продаете или у вас там зашифрован алгоритм по созданию Скайнета?
Подводя итоги, можно сделать вывод, что иногда без функции eval просто не обойтись. И большинство принимают правильное решение: её можно использовать, но чем меньше — тем лучше.
От себя хочется добавить ярым противникам eval:
Неважно, как появился код: загружен сторонний скрипт, с помощью Function, с помощью eval — все равно он может быть потенциально опасным. А так называемое зло eval (потенциальный доступ к переменным, медленность работы) преувеличено, потому что всё зависит только от степени понимания программистом тонкостей языка. Если ты быдлокодер, то и без eval наделаешь уязвимостей.
От себя хочется добавить ярым противникам eval:
Неважно, как появился код: загружен сторонний скрипт, с помощью Function, с помощью 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 от сервера.
Возможно, я не прав, поправьте.
Например, при авторизации или добавлении записи куда-то я делаю запрос к серверу и от отдает мне 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+')');
}
var parseJSON = (window.JSON && JSON.parse)? function (obj) {
try { return JSON.parse(obj); } catch (e) {
return eval('('+obj+')');
}
}: function(obj) {
return eval('('+obj+')');
}
Sign up to leave a comment.
Как вы относитесь к функции eval в JavaScript?