JavaScript: повесить функцию с параметром на событие
От: Eugeny__ Украина  
Дата: 13.01.06 13:54
Оценка:
Доброго времени суток.

Встретился с проблемой, которую никак не могу решить.

Есть таблица. (которая <table>)
Есть функция
function doAny(parameter){
...
}


Задача следующая:
1. Проанализировать значения всех ячеек. (алгоритм есть)
2. Если встречается определенная ячейка, сделать из ее содержимого строку str
3. Очистить ячейку, из которой str получена
4. На строку таблицы на событие OnClick повесить doAny(str);

До п.4 все хорошо. Но как повесить в качестве обработчика функцию с параметром?
Если писать в html коде, то все просто:
<tr onClick="doAny('str value')">.
А как это сделать из скрипта?
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re: JavaScript: повесить функцию с параметром на событие
От: DrZubr Беларусь  
Дата: 13.01.06 14:11
Оценка: 1 (1)
Здравствуйте, Eugeny__, Вы писали:

E__>skipped


E__>До п.4 все хорошо. Но как повесить в качестве обработчика функцию с параметром?

E__>Если писать в html коде, то все просто:
E__><tr onClick="doAny('str value')">.
E__>А как это сделать из скрипта?

Тебе что именно нужно? Чтобы функция была именно с параметром? Тут точно такой смысл нужен? Или все таки тебе нужна функция, которая бы делала определенное действие, в зависимости от того, на какаой элемент ты ее вешаешь? Если да — как вариант могу предложить конструировать новую функцию на каждый элемент.

<html>
<body>
<script>
function delegate(value) {
    alert(value);
}
var value = prompt('Enter string: ');
document.getElementsByTagName('body')[0].onclick = new Function('delegate(unescape("' + escape(value) + '"))');
</script>
Click on this text
</body>
</html>
... << RSDN@Home 1.2.0 alpha rev. 619>>
ICQ [168117153]
Re: JavaScript: повесить функцию с параметром на событие
От: Кодт Россия  
Дата: 13.01.06 14:24
Оценка: 5 (2) +1
Здравствуйте, Eugeny__, Вы писали:

E__>А как это сделать из скрипта?


С помощью анонимных функций.
function makeFunc(s)
{
  return function() { doAny('hello'+s); }; // эта функция учитывает контекст, где она создана (т.е. значение s)
}

cell1.onclick = makeFunc("123");
cell2.onclick = makeFunc("456");


Если бы сделать вот так
var s;

s = "123";
cell1.onclick = function() { doAny('hello'+s); }

s = "456";
cell2.onclick = function() { doAny('hello'+s); }

то обе функции, обращаясь к s по имени, вызвали бы doAny('hello456').
А в первом случае они обращаются к разным контекстам, и выводят doAny('hello123'), doAny('hello456') соответственно.
Перекуём баги на фичи!
Re[2]: JavaScript: повесить функцию с параметром на событие
От: Eugeny__ Украина  
Дата: 13.01.06 16:26
Оценка:
Здравствуйте, Кодт, Вы писали:

E__>>А как это сделать из скрипта?


К>С помощью анонимных функций.


избыточное цитирование удалено — Кодт

Спасибо, это работает. В IE. А для оперы вариантов нету? Хотя это уже ради академического интереса, по заданию хватит и ie.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[3]: JavaScript: повесить функцию с параметром на событие
От: Кодт Россия  
Дата: 14.01.06 09:11
Оценка:
Здравствуйте, Eugeny__, Вы писали:

E__>Спасибо, это работает. В IE. А для оперы вариантов нету? Хотя это уже ради академического интереса, по заданию хватит и ie.


И в Опере работает. Вот прямо сейчас протестировал на 8.5.0 ru.
<table id=tbl border=1><tr>
<td id=t1>1</td>
<td id=t2>2</td>
<td id=t3>3</td>
<td id=t4>4</td>
</tr></table>
<script>

// конструктор лямбды
function makeFunc(s) { return function(){ alert('it is '+s); } }

// убедимся, что переменная-аргумент используется по значению, а не по ссылке
var v;
v = 100; t1.onclick = makeFunc(v);
v = 200; t2.onclick = makeFunc(v);

// проверим DOM стандартный
var t = document.getElementById('t3');
if(t) t.onclick = makeFunc(300);

// проверим DOM IE
t = document.all['t4'];
if(t) t.onclick = makeFunc(400);

t = tbl.rows(0).insertCell(-1); // добавим новую ячейку
t.innerText = '5';
t.onclick = makeFunc(500);

</script>
Перекуём баги на фичи!
Re[2]: JavaScript: повесить функцию с параметром на событие
От: DSD Россия http://911.ru/cv
Дата: 16.01.06 09:12
Оценка: 46 (1)
Здравствуйте, Кодт, Вы писали:

К>
К>function makeFunc(s)
К>{
К>  return function() { doAny('hello'+s); }; // эта функция учитывает контекст, где она создана (т.е. значение s)
К>}

К>cell1.onclick = makeFunc("123");
К>cell2.onclick = makeFunc("456");
К>


это все разворачивается в следующее:
cell1.onclick = function() { doAny('hello123'); };
cell2.onclick = function() { doAny('hello456'); };


отсюда делаем вывод: параметрами здесь и не пахнет в принципе. только удобством в структуре кода.
что в контексте задачи аналогично следующему:
function cell_click() { 
   doAny(this.str); 
}

cell1.str="123";
cell1.onclick = cell_click;

cell2.str="456";
cell2.onclick = cell_click;

с тем лишь исключением, что в последнем варианте все присвоенные обработчики ссылаются на один экземпляр функции, а не жрут память каждый под свой экземпляр.
--
DSD
Re: JavaScript: повесить функцию с параметром на событие
От: Аноним  
Дата: 16.01.06 19:19
Оценка:
Здравствуйте, Eugeny__, Вы писали:

E__>Доброго времени суток.


E__>Встретился с проблемой, которую никак не могу решить.

Передается же обработчику события объект, вызвавший событие. Толи в this, толи еще как, уж склероз изменяет мне что-то, но точно передается... И все. Хочешь параметры нужные загодя цепляй к ячейке, хочешь значение проверяй. Ну можно и цункции, конечно, назначать, как тут предложено, но это как-то менее гуманно...
Re[3]: JavaScript: повесить функцию с параметром на событие
От: Кодт Россия  
Дата: 17.01.06 11:01
Оценка:
Здравствуйте, DSD, Вы писали:

<>
DSD>с тем лишь исключением, что в последнем варианте все присвоенные обработчики ссылаются на один экземпляр функции, а не жрут память каждый под свой экземпляр.

Да, это очень хорошее замечание.
Опять же, если параметр меняется — достаточно изменить значение свойства у объекта, а не пересоздавать функцию.

Тем более, что анонимные функции весьма расточительны, т.к. запоминают весь контекст, в котором были созданы — включая все видимые ими переменные.
Перекуём баги на фичи!
Re[3]: JavaScript: повесить функцию с параметром на событие
От: Eugeny__ Украина  
Дата: 17.01.06 16:40
Оценка:
Здравствуйте, DSD, Вы писали:

DSD>
DSD>function cell_click() { 
DSD>   doAny(this.str); 
DSD>}

DSD>cell1.str="123";
DSD>cell1.onclick = cell_click;

DSD>cell2.str="456";
DSD>cell2.onclick = cell_click;
DSD>

DSD>с тем лишь исключением, что в последнем варианте все присвоенные обработчики ссылаются на один экземпляр функции, а не жрут память каждый под свой экземпляр.

Хм.. В примере Кодта(и предыдущем, в принципе) вроде все ясно — создается новый экземпляр функции. Я так пока и сделал(благо, мне ресурсная стоимость кода в данном случае не очень важна — строк в таблице на каждой странице будет не более 20).
В приведенном примере меня интересует пара вопросов:
1. когда мы пишем cell1.str = "123" мы добавляем к объекту cell1 свойство str? Интересный подход... Я и не знал, что так можно
2. Получается, что при присваивании объекту обработчика событий запоминается как минимум текущий контекст объекта. Запоминается контекст объекта, или же все-таки глобальный контекст?

Кстати, а что происходит при написании
<tr onClick = "cell_click('789')"> ?
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[4]: JavaScript: повесить функцию с параметром на событие
От: DSD Россия http://911.ru/cv
Дата: 17.01.06 22:14
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Тем более, что анонимные функции весьма расточительны, т.к. запоминают весь контекст, в котором были созданы — включая все видимые ими переменные.

не все. только локальные и переданные параметры.
в твоем начальном примере:
function makeFunc(s)
{
  return function() { doAny('hello'+s); }; // эта функция учитывает контекст, где она создана (т.е. значение s)
}

cell1.onclick = makeFunc("123");
cell2.onclick = makeFunc("456");


в функции makeFunc сначала вычисляется выражение 'hello'+s, а потом уже единой строковой константой-литералом остается параметром к doAny. иначе говоря в результате получается то же, что я и указал в моем предыдущем посте:
cell1.onclick = function() { doAny('hello123'); };
cell2.onclick = function() { doAny('hello456'); };

о переменной же s она благополучно забывает.

глобальные же переменные она продолжает видеть по ссылке, т.е. если такая глобальная переменная изменится после создания функции, то при последующем вызове этой функции она из этой переменной прочтет измененный результат, то есть текущее значение на момент вызова.
--
DSD
Re[4]: JavaScript: повесить функцию с параметром на событие
От: DSD Россия http://911.ru/cv
Дата: 17.01.06 22:25
Оценка:
Здравствуйте, Eugeny__, Вы писали:

E__>Здравствуйте, DSD, Вы писали:


DSD>>
DSD>>function cell_click() { 
DSD>>   doAny(this.str); 
DSD>>}

DSD>>cell1.str="123";
DSD>>cell1.onclick = cell_click;

DSD>>cell2.str="456";
DSD>>cell2.onclick = cell_click;
DSD>>

DSD>>с тем лишь исключением, что в последнем варианте все присвоенные обработчики ссылаются на один экземпляр функции, а не жрут память каждый под свой экземпляр.

E__>1. когда мы пишем cell1.str = "123" мы добавляем к объекту cell1 свойство str? Интересный подход... Я и не знал, что так можно

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


E__>2. Получается, что при присваивании объекту обработчика событий запоминается как минимум текущий контекст объекта. Запоминается контекст объекта, или же все-таки глобальный контекст?

контекст объекта не запоминается. просто при вызове функции-обработчика ссылка на содержащий ее объект будет неявно в нее передана, и он будет в ней доступен как this.

E__>Кстати, а что происходит при написании

E__><tr onClick = "cell_click('789')"> ?
происходит фактически следующее:
 tr.onClick = function() { cell_click('789') }

или возможно подобное:
 tr.onClick = function() { eval("cell_click('789')"); }


пожалуй с той лишь разницей, что корректно обрабатываются конструкции вида <tr onClick = "javascript:cell_click('789')"> и некоторые другие.
текущий объект внутри этих функций по прежнему будет доступен по this, пока не перекроется вызовом метода другого объекта, например:

 obj2.do_on_click=function(s) {
    // this=obj2
    alert(s);
 }

 function cell_click(s) {
    // this=tr
    obj2.do_on_click(s);
 }

 tr.onClick = function() { 
     // this=tr
     cell_click('789');
 }


так понятнее?
--
DSD
Re[5]: JavaScript: повесить функцию с параметром на событие
От: Кодт Россия  
Дата: 18.01.06 10:21
Оценка:
Здравствуйте, DSD, Вы писали:

DSD>Здравствуйте, Кодт, Вы писали:


К>>Тем более, что анонимные функции весьма расточительны, т.к. запоминают весь контекст, в котором были созданы — включая все видимые ими переменные.

DSD>не все. только локальные и переданные параметры.

Именно поэтому я и сделал функцию-генератор makeFunc(s), которая сужает контекст.
А вот если я в скрипте напишу
var x, y, z..... // куча всякого хлама
.....
cell1.onclick = function() { } // весь этот хлам будет запомнен, хотя и не нужен
.....


DSD>в функции makeFunc сначала вычисляется выражение 'hello'+s, а потом уже единой строковой константой-литералом остается параметром к doAny. иначе говоря в результате получается то же, что я и указал в моем предыдущем посте:


Неправда. Переменная s будет существовать именно как переменная, и 'hello'+s вычислится именно в анонимной функции, а не при её конструировании.
Вот иллюстрация
<table border=1><tr><td id=cell>click me!</td></tr></table>
<div id=other str='DSD'></div> <!-- просто долгоживущий объект, ничего больше -->
<script>
function make(obj) { return function() { alert("hello "+obj.str); } }

cell.onclick = make(other); // сперва конструируем функцию
other.str = 'Kodt'; // и только потом меняем значение, которое она использует
</script>

Посмотри, кого он поприветствует.
Перекуём баги на фичи!
Re[6]: JavaScript: повесить функцию с параметром на событие
От: DSD Россия http://911.ru/cv
Дата: 18.01.06 11:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, DSD, Вы писали:


DSD>>Здравствуйте, Кодт, Вы писали:


К>>>Тем более, что анонимные функции весьма расточительны, т.к. запоминают весь контекст, в котором были созданы — включая все видимые ими переменные.

DSD>>не все. только локальные и переданные параметры.

К>Именно поэтому я и сделал функцию-генератор makeFunc(s), которая сужает контекст.

К>А вот если я в скрипте напишу
К>
К>var x, y, z..... // куча всякого хлама
К>.....
К>cell1.onclick = function() { } // весь этот хлам будет запомнен, хотя и не нужен
К>.....
К>

не будет он запомнен. измени любую переменную из хлама и вызови cell1.onclick — внутри него хлам будет виден в его текущем состоянии, а не запомненным на момент создания.



DSD>>в функции makeFunc сначала вычисляется выражение 'hello'+s, а потом уже единой строковой константой-литералом остается параметром к doAny. иначе говоря в результате получается то же, что я и указал в моем предыдущем посте:

К>Неправда. Переменная s будет существовать именно как переменная, и 'hello'+s вычислится именно в анонимной функции, а не при её конструировании.

К>Вот иллюстрация

К>
К><table border=1><tr><td id=cell>click me!</td></tr></table>
К><div id=other str='DSD'></div> <!-- просто долгоживущий объект, ничего больше -->
К><script>
К>function make(obj) { return function() { alert("hello "+obj.str); } }

К>cell.onclick = make(other); // сперва конструируем функцию
К>other.str = 'Kodt'; // и только потом меняем значение, которое она использует
К></script>
К>

К>Посмотри, кого он поприветствует.

а ты вместо "долгоживущего объекта" создай "долгоживущую строку", и увидишь, что расклад резко поменяется
<table border=1><tr><td id=cell>click me!</td></tr></table>
<div id=other str='DSD'></div> <!-- просто долгоживущий объект, ничего больше -->
<script>
var test_str='DSD';
function make(s) { return function() { alert("hello "+s); } }

cell.onclick = make(test_str); // сперва конструируем функцию
test_str = 'Kodt'; // и только потом меняем значение, которое она использует
</script>


в принципе согласен, насчет преждевременных вычислений я погорячился конечно, но и с контекстом там все не так просто.
в JS есть понятие базовых объектов(String, Number, Array, Date etc.)
фишка в том, что в контексте запоминаются базовые объекты по значению, остальные — по ссылке..
в случае с obj.str запомнился по ссылке именно obj, а до его свойства str дело доходит в момент выполнения функции.
с глобальными переменными та же фигня, с той лишь разницей, что все глобальные переменные являются свойствами объекта-суперглобала window, поэтому сами значения этих свойств на момент создания функции не запоминаются, а запоминается лишь ссылка на window.
так же очевидно, что в моменте:
function make(s) { return function() { alert("hello "+s); } }

внутри безымянной функции переменная s скорее всего должна разыменовываться, т.к. происходит разрыв контекстов двух функций... но вот тут мне логика создателей языка не очень понятна...
возможно она и в самом деле разыменовывается и ее копия сохраняется в контексте функции при создании, так же как и в твоем последнем примере сохранялась разыменованнная ссылка на obj...

--
DSD
Re[7]: JavaScript: повесить функцию с параметром на событие
От: Кодт Россия  
Дата: 18.01.06 12:16
Оценка:
Здравствуйте, DSD, Вы писали:

К>>
К>>var x, y, z..... // куча всякого хлама
К>>.....
К>>cell1.onclick = function() { } // весь этот хлам будет запомнен, хотя и не нужен
К>>.....
К>>

DSD>не будет он запомнен. измени любую переменную из хлама и вызови cell1.onclick — внутри него хлам будет виден в его текущем состоянии, а не запомненным на момент создания.

Я имею в виду — он будет запомнен по ссылке, а не по значению. Всё равно этот хлам останется в памяти.

DSD>>>в функции makeFunc сначала вычисляется выражение 'hello'+s, а потом уже единой строковой константой-литералом остается параметром к doAny. иначе говоря в результате получается то же, что я и указал в моем предыдущем посте:

К>>Неправда. Переменная s будет существовать именно как переменная, и 'hello'+s вычислится именно в анонимной функции, а не при её конструировании.

DSD>а ты вместо "долгоживущего объекта" создай "долгоживущую строку", и увидишь, что расклад резко поменяется


DSD>в принципе согласен, насчет преждевременных вычислений я погорячился конечно, но и с контекстом там все не так просто.

DSD>в JS есть понятие базовых объектов(String, Number, Array, Date etc.)
DSD>фишка в том, что в контексте запоминаются базовые объекты по значению, остальные — по ссылке..

Вот именно.
function make(s)
{
  var f = return function() { alert("hello "+s); s += "+"; } // создали функцию
  s += "{ ku-ku }";

  return f;
}

И покликай несколько раз. Увидишь, что мы имеем дело именно с одной и той же переменной s из контекста make — хотя бы потому, что она выведет "hello DSD{ ku-ku }+++"
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.