LINUX.ORG.RU

Управляющие конструкции в JS

 ,


0

5

Во многих языках, таких как лисп или тикль, например, принято расширять язык управляющими конструкциями. Эти конструкции, реализуют более удобный функционал, или функционал, заточенный под определенную задачу. К сожалению, в javascript эта практика не слишком распространена, а между тем, я заметил, что в JS это вполне возможно, и даже удобно. Например, есть цикл for in. Тут сразу бросается в глаза то, что в качестве переменной-итератора, можно использовать любое имя, и обычно используется имя i или name. Ясно, что писать это явным образом не нужно, но для этого мы должны сделать некоторое обобщение и реализовать его в виде процедуры. Например:


print=console.log
for_each=function(ob, expr){for(var name in ob){value=ob[name]; eval(expr)}}

for_each({a: 1, b: 2}, "print(name+': '+value)")

//  a: 1
//  b: 2

for_each([1,2,3,4,5], "if(value!==3) print(name+': '+value)")

//  0: 1
//  1: 2
//  3: 4
//  4: 5

Уровень абстракции повышается, нет необходимости отвлекатся на реализацию итерации, концентрируемся непосредственно на действиях.

Тут есть даже некоторое преимущество перед CL и Scheme, поскольку конструкция реализуется в виде обычной функции, и, соответственно не требует препроцессора, а значит, является органичным языковым объектом, а не прибитым гвоздями костылем, существующем исключительно в компилтайме.

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

Хотелось бы узнать, нет ли какой-нибудь книжки, или ресурса, где рассматриваются паттерны написания управляющих конструкций, ДСЛ-ей, метапрограммирования на JS?



Последнее исправление: terminator-101 (всего исправлений: 3)

eval(expr)

преимущество перед CL и Scheme

В CL и Scheme нет eval? Ну тогда возьми лисп где он есть, делов-то.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

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

terminator-101
() автор топика

использовать eval лишь для более удобного синтаксиса?

ну тогда не забывай тогда везде вставлять экранизацию, и вообще почаще заглядывать в манагер процессов (top, ps)..

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

блин, мне казалось что после shockshell — ты должен был поумнеть.

тык нет же — ты опять за своё...

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 1)
Ответ на: комментарий от user_id_68054

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

Че за бред? В тикле используется эвал в каждой строке, на нем тоже сервер написан, что-то не жалуется никто на инъекции. О чем вообще речь то идет? Ты что будешь эвалить строки, пришедшие на сервер, или че?

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

> shockshell

Это че такое?

кара спустившеяся на землю для bash-программистив.

это было совсем недавно — месяц назад.

однако в случае shockshell — пострадали не только виновные bash-программисты, но и множество невиновных.. кара настигла их практически без разбора..

а тебя похоже не настигла... эх... жаль :-( ...

блин, ну вставь ты в начале js-файла декларацию 'use strict' , и не парь мозги. :)

во время использования 'use strict' — хоть и можно выстрелить себе в ногу (что ты и пытаешься сделать), но ччуточку сложнее...

user_id_68054 ★★★★★
()

eval не нужен

foreach = function(ob, callback) {
  for(var i in ob) {
    callback(ob[i], i, ob);
  }
}

var pf = function(value, name, obj) {
  console.log(value, name, obj);
}

foreach({a: 1, b: 2}, pf);
foreach([1,2,3,4,5], pf);
kiotoze ★★★★
()
Ответ на: комментарий от terminator-101

В тикле используется эвал в каждой строке, на нем тоже сервер написан

при чём тут тикель?

мало ли как там на тикле..

я тебе пишу по делу, относительно js:

1. если будешь использовать в js — операцию eval ни к месту — то обеспечишь хорошую почву для легковзламываемого (уязвимого) кода.

2. если не будешь использовать декларацию 'use strict' в каждом файле своего кода — то вероятнее всего наделаешь в своём коде кучу ошибок (возмоно просто ошибок, а не уязвимостей).

хотя пункт 2 и пункт 1 — совершенно неуместно тебе рассказывать в случае, если ты просто терию разводишь а не код пишешь.. :)

user_id_68054 ★★★★★
()
Ответ на: комментарий от kiotoze

это да.

а ещё в js есть Array.prototype.every() :-)

[а для старых браузеров — есть polyfill для Array.prototype.every() ]

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 1)
Ответ на: комментарий от Deleted

он же написал что скорость не главное..

главное чтобы код выглядел бы как говно :-) [и имел бы говянные свойства]... это и есть метапраграммирование, в понимании автора :)

user_id_68054 ★★★★★
()
Ответ на: комментарий от user_id_68054

можешь выдать мне (сюда в тему) исходный код и ip-адрес сервера ?.. быть может у меня (или ещё у кого) найдётся время, чтобы разобрать твой говнокод и сделать тебе карательную js-инекцию? :-)

Ты хоть и удалил, по причине, причем тут тикль, но предложение мне твое понравилось. Вот тебе игрушечный сервер на JS, с евалом. Расскажи, как ты сюда что-нибудь внедришь, мне всегда было интересно, но никогда не понимал.

var http = require('http');
var fs = require('fs');
for_each=function(ob, expr, env) {for(var name in ob){value=ob[name]; eval(expr)}}

files=["foo", "bar", "baz"]
cut=function(request){return request.replace(/\//, "")}

http.Server(function(req, res){
    var file
    for_each(files, "if(env.r===value) env.set(value)", {r: cut(req.url), set: function(x){file=x}})
    if(!file) return res.end("no such document")
    fs.readFile(file, "utf8", function(err, data){res.write(data); res.end()})
}).listen(3030);
Я пытался свалить, у меня не получилось. В частности, я отправлял localhost:3030/throw(err) , эта строка приходит без всякого кодирования, в таком виде попадает в eval, но ничего не происходит. eval(throw(1)) — тоже. ЧЯДНТ? Жду твои предложения. Не правда, ужасно интересно, как это делается:)

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

в данном случае — на основе eval() сделать карательную js-инъекцию — не получится. ну или я пока-что не вижу как можно было бы..

потому что вызывается for_each() [который на основе eval()] только один раз , и в этом вызове нет ни чего небезопасносго.

(если бы вызывалось бы много и в разных местах — то быть может что-то небезопасное и нашлось бы. хотя бы в одном месте забыл бы заэкранировать :-} ... а сейчас тут даже экранировать тебе нечего)

# P.S.: понимаешь чем helloworld отличается от кода полнофункциональной программы? ответ: размером и сложностью кода :-)

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 2)
Ответ на: комментарий от terminator-101

ладно, с взломами, понятно..

..но можешь объснить — нафига ты вообще тут использовал eval() ?

нельзя разве было просто передать ссылку на функцию?

сделать так как это делается в Array.prototype.every() — почему тебе не хочется?

твоя eval() — только запутала всё, так как вместе с eval-выражением ты передаёшь ещё и env.. это добавляет безопасность в eval() — но удаляет понятность в ней.

с таким же успехом — вместо env ты можешь сразу передать function() {....выражение...} — возникает вопрос — нахрена тогда вообще eval() ?

...и как ты станешь использовать свои eval() в ситуации когда в файле будет декларация 'use strict' ? (будешь делать отдельные опасные модули без 'use strict' ?)

# P.S.: скажи честно — ты просто хочешь заспользовать ХОТЬ-КАК-ТО eval(), но не знаешь в какое место лучше её вставить? :-) угадал?

# P.P.S.: а потом ты скажешь — «вот видите! ваша 'use strict' говно, так как оно мне не разрешает использовать eval()!!» :-D .. да? угодал тоже? :-)

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 11)
Ответ на: комментарий от user_id_68054

Изначально, я просто хотел создать пример управляющей конструкции. Код for-each(ob, «dosmthwith(name, value)») компактней и ясней, чем с колбеками, и не надо явно передавать аргументы. env пришлось добавить чтобы пробросить аргументы из локального скопа колбака сервера, иначе не работает. Это усложняет немного, но он опционален, все же лучше лапши из колбеков. А use strict я вообще не использую, это для баб.

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

А use strict я вообще не использую, это для баб.

да, компьютеры и программирование — это для баб. :-)

мужики, нормальные — должны в армии служить и ящики из вагонов разгружать потом. мебель таскать на 10 этаж без лифта.. и т д..

env пришлось добавить чтобы пробросить аргументы из локального скопа колбака сервера, иначе не работает

какая неожиданность! (сарказм:))

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

'use strict'  — пытается намекать тебе на то что eval говно, а ты сопротивляешься :-D

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 6)
Ответ на: комментарий от user_id_68054

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

Потому что я не люблю лапшу из колбеков. Так код легче воспринимается. И он гибче. Не нужна явная предача аргументов, последовательность аргументов запоминать не нужно.

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

Потому что я не люблю лапшу из колбеков.

окей, делай колбеки — без лапши. :)

или тебя кто-то заставляет делать колбеки — лапшиобразно? :-)

Так код легче воспринимается. И он гибче.

кто легче воспринимается? кто гибче? eval? env-выражение с передачей контекста?

ты очень умелый тролль — мне уже хочется разбить монтор комьютера :-) ..

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 2)
Ответ на: комментарий от user_id_68054

кто легче воспринимается? кто гибче? eval? env-выражение с передачей контекста?

Да, потому что в этом случае:

foreach = function(ob, callback) {
  for(var i in ob) {
    callback(ob[i], i, ob);
  }
}
foreach({a: 1, b: 2}, function(value, name, ob){console.log(name+": "+value)});

Мне при написании колбака всегда приходится вспоминать очередность аргументов, какой к чему относится. А так мне нужны только имена. И даже когда я пробрасываю дополнительные аргументы через env, мне не приходится заново сканировать функцию, я буду всегда знать, что все имена просто окажутся в нужном скопе, и я их могу использовать произвольно. Это только на первый взгляд мелочь, а в сложном коде вспоминать порядок передачи аргументов напряжно. Это отвлекает от логики кода, сбивает с мысли.

terminator-101
() автор топика

Во многих языках, таких как лисп или тикль, например, принято расширять язык управляющими конструкциями

Да-да. Поубивать тех умников, которые херачат макросы, перегрузку операторов, мета-классы и прочую лабуду. В большинстве случаев это абсолютный оверинжиниринг и никто кроме авторов написанного пользоваться этим не станет. Лучше писать в рамках конструкций выбранного языка. А к мета-хрени прибегать только в особо сложных случаях

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.