JavaScript

Использование и разработка софта (преимущественно на ПЦ)

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

JavaScript

Post by Shaos »

Последние несколько лет язык JavaScript более-менее застандартизировали и им уже стало можно пользоваться без оглядки на особенности реализации тех или иных вещей в тех или иных браузерах. К тому же JavaScript можно назвать функциональным языком программирования - в нём можно функции передавать в другие функции и возвращать из других функций. Поэтому открываю топик для обсуждения всяких трюков и тонкостей, которые были бы полезны не только мне.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

В функциональном программировании в JS есть одна несуразность, которая меня смущает (здесь и далее буду приводить выхлоп интерпретатора JS от мозиллы под названием Spidermonkey):

Code: Select all

js> function a(b){return function(c){return b+c;};};
js> a(1)
function (c) {
    return b + c;
}
js> a(1)(2)
3
Как видим я определил функцию a, которая возвращает другую функцию - если выполнить a(1)(2), то оно вполне ожидаемо вернёт 3, а вот если выполнить a(1), то оно возвращает текст функции без изменений, однако я ожидал, что переменная b должна быть заменена на 1, т.е.:

Code: Select all

function (c) {
    return 1 + c;
}
У кого есть какие мысли на этот счёт?

P.S. в Firefox и Konqueror оно ведёт себя точно также
Я тут за главного - если что шлите мыло на me собака shaos точка net
b2m
Devil
Posts: 907
Joined: 26 May 2003 06:57

Post by b2m »

Shaos wrote:У кого есть какие мысли на этот счёт?
Переменные в JS вычисляются только тогда, когда нужно их значение. А до тех пор они так и остаются переменной с определённым именем, т.к. в JS нет определённого деления на локальные и глобальные переменные (в том месте, где берётся значение переменной). Если нет локальной, то будет искаться глобальная.

В данном случае вызовы функций вложенные, т.е. к моменту вызова внутренней, внешняя имела в стеке локальных переменных (который общий для всех функций) значение b. Но вообще, это должно зависеть от реализации (уничтожать ли локальные переменные внешней функции при возврате тела внутренней функции как значения). С другой стороны, выражение a(1)(2) к моменту вычисления внутренней функции ещё не вычислено, а значит фактические параметры вызова a() ещё должны быть в стеке. Что мы и наблюдаем.

Получается, за уничножение локальных переменных в JS отвечает вызывающая программа (как в cdecl), а не вызванная (как в stdcall). :)
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

b2m wrote:
Shaos wrote:У кого есть какие мысли на этот счёт?
Переменные в JS вычисляются только тогда, когда нужно их значение. А до тех пор они так и остаются переменной с определённым именем, т.к. в JS нет определённого деления на локальные и глобальные переменные (в том месте, где берётся значение переменной). Если нет локальной, то будет искаться глобальная.

В данном случае вызовы функций вложенные, т.е. к моменту вызова внутренней, внешняя имела в стеке локальных переменных (который общий для всех функций) значение b. Но вообще, это должно зависеть от реализации (уничтожать ли локальные переменные внешней функции при возврате тела внутренней функции как значения). С другой стороны, выражение a(1)(2) к моменту вычисления внутренней функции ещё не вычислено, а значит фактические параметры вызова a() ещё должны быть в стеке. Что мы и наблюдаем.

Получается, за уничножение локальных переменных в JS отвечает вызывающая программа (как в cdecl), а не вызванная (как в stdcall). :)
но тем не менее - вызов a(1) можно присвоить переменной и затем применить второй аргумент уже к ней:

Code: Select all

js> function a(b){return function(c){return b+c;};}; 
js> var aa = a(1);
js> aa(2)
3
js> aa
function (c) {
    return b + c;
}
Я тут за главного - если что шлите мыло на me собака shaos точка net
b2m
Devil
Posts: 907
Joined: 26 May 2003 06:57

Post by b2m »

В таком случае, фактические параметры (для необъявленых локальных переменных) должны сохраняться вместе с телом функции, просто JS их не выводит, когда переводит тело функции обратно в текстовый вид.

Можно ещё проверить, будут ли сохраняться значения глобальных переменных, которые используются в теле функции. Хотя, я полагаю, что они не будут сохраняться, на то они и глобальные.

А вот локальные переменные, объявленные во внешней функции, и используемые во внутренней, скорее всего тоже будут сохраняться вместе с телом, как и фактические параметры.
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

b2m wrote:В таком случае, фактические параметры (для необъявленых локальных переменных) должны сохраняться вместе с телом функции, просто JS их не выводит, когда переводит тело функции обратно в текстовый вид.
И это делает отлаживание функционального программирования на JS практически невозможным...
Я тут за главного - если что шлите мыло на me собака shaos точка net
Different
Doomed
Posts: 408
Joined: 18 Feb 2007 11:40

Post by Different »

Shaos wrote:И это делает отлаживание функционального программирования на JS практически невозможным...
a(1) никогда не вернет то, что ты ожидал :)
И это правильно. Function statement requires a name!
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Different wrote:
Shaos wrote:И это делает отлаживание функционального программирования на JS практически невозможным...
a(1) никогда не вернет то, что ты ожидал :)
И это правильно. Function statement requires a name!
Безымянные функции в JS вполне допустимы и широко применяются на практике
Я тут за главного - если что шлите мыло на me собака shaos точка net
Different
Doomed
Posts: 408
Joined: 18 Feb 2007 11:40

Post by Different »

Shaos wrote:Безымянные функции в JS вполне допустимы и широко применяются на практике
Да, если аргумент в наличии. А так получается - ни имени, ни аргумента.
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Different wrote:
Shaos wrote:Безымянные функции в JS вполне допустимы и широко применяются на практике
Да, если аргумент в наличии. А так получается - ни имени, ни аргумента.
Ну и в чём проблема? Можно передать анонимную функцию из другой функции и применить к ней аргумент позже - всё работает как надо, просто при логировании печать неверная...
Я тут за главного - если что шлите мыло на me собака shaos точка net
Different
Doomed
Posts: 408
Joined: 18 Feb 2007 11:40

Post by Different »

Shaos wrote: Ну и в чём проблема? Можно передать анонимную функцию из другой функции и применить к ней аргумент позже - всё работает как надо, просто при логировании печать неверная...
Так нет никаких проблем, если правильно писать скрипты.
А в чем печать при логгировании неверная? Оно и в реальной ситуации через alert() выдаст тоже самое.
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Different wrote:
Shaos wrote: Ну и в чём проблема? Можно передать анонимную функцию из другой функции и применить к ней аргумент позже - всё работает как надо, просто при логировании печать неверная...
Так нет никаких проблем, если правильно писать скрипты.
А в чем печать при логгировании неверная? Оно и в реальной ситуации через alert() выдаст тоже самое.
Какой алерт? См. внимательно - объясняю по шагам "на пальцах":

Объявляем функцию с одним аргументом: function a(b){return function(c){return b+c;};};
которая возвращает другую анонимную функцию, внутри которой использован этот один внешний аргумент

При вызове a(1)(2) оно корректно возвращает 3

А вот при вызове a(1) оно вместо

Code: Select all

function (c) {
    return 1 + c;
}
возвращает

Code: Select all

function (c) {
    return b + c;
}
То что это лишь ошибка печати я показал тем, что сохранил эту возвращённую функцию в переменной (тем самым дав имя этой анонимной функции):
var aa = a(1);
после чего вызов aa(2) вполне ожидаемо даёт 3, т.е. aa действительно имеет в себе function(c){return 1+c;}

т.е. я склоняюсь к объяснению, полученному от b2m:
b2m wrote:фактические параметры (для необъявленых локальных переменных) должны сохраняться вместе с телом функции, просто JS их не выводит, когда переводит тело функции обратно в текстовый вид.
Я тут за главного - если что шлите мыло на me собака shaos точка net
Different
Doomed
Posts: 408
Joined: 18 Feb 2007 11:40

Post by Different »

Shaos wrote: То что это лишь ошибка печати я показал тем, что сохранил эту возвращённую функцию в переменной (тем самым дав имя этой анонимной функции)
Нет там никаких ошибок печати :) RTFM
Этой анонимной функции ты имя не давал, так как только присвоил объект переменной.
А так как параметр не передается в анонимную функцию, то и вызова функции не происходит, и return возвращает только тело функции, что вполне закономерно и ожидаемо.

"Для того чтобы научится правильно пользоваться функциями в JavaScript их нужно воспринимать как обычные данные": (c) http://xdan.ru/Funcional-JavaScript.html
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Different wrote:
Shaos wrote: То что это лишь ошибка печати я показал тем, что сохранил эту возвращённую функцию в переменной (тем самым дав имя этой анонимной функции)
Нет там никаких ошибок печати :) RTFM
Этой анонимной функции ты имя не давал, так как только присвоил объект переменной.
А так как параметр не передается в анонимную функцию, то и вызова функции не происходит, и return возвращает только тело функции, что вполне закономерно и ожидаемо.
как это ожидаемо тело функции, если никакого b там уже нет и быть не может?

Code: Select all

js> function a(b){return function(c){return b+c;};};
js> var aa = a(1);
js> aa(2)
3
js> aa
function (c) {
    return b + c;
} 
и что-то я не улавливаю как безымянность функции соотносится со связанностью используемых внутри неё переменных..
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24083
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Ещё более подробно для тех кто ещё не понял суть проблемы:

Code: Select all

js> function a(b){return function(c){return b+c;};}; 
js> var plus1=a(1);
js> var plus2=a(2);
js> var plus3=a(3);
js> plus1(100)
101
js> plus2(100)
102
js> plus3(100)
103
js> plus1
function (c) {
    return b + c;
}
js> plus2
function (c) {
    return b + c;
}
js> plus3
function (c) {
    return b + c;
}
Как видим при печати plus1,puls2.plus3 выдают одно и тоже, хотя вместо b в первом случае должно быть 1, во втором 2, в третьем 3, ну или хотя бы что-то типа такого меня тоже устроило бы:

Code: Select all

js> plus1
function (c) {
    return b + c;
}
where b=1

js> plus2
function (c) {
    return b + c;
}
where b=2

js> plus3
function (c) {
    return b + c;
}
where b=3
Я тут за главного - если что шлите мыло на me собака shaos точка net