免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5598 | 回复: 1
打印 上一主题 下一主题

[学习] Event Handlers and Callback Functions [复制链接]

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-12-15 21:44 |只看该作者 |倒序浏览
[学习] Event Handlers and Callback Functions


Event Handlers and Callback Functions - article
In Javascript
Required knowledge
You'll have to know how to program object oriented with Javascript. Read the articles at Webreference (links at the left of the article) to catch up on that.
Last Update
10/16/2005; 1:23:17 AM
Try XHTML 2.0
Src XHTML 2.0
RDF Metadata
Site Search
Site Colors
Site E-mail Me
Syn Atom 1.0
Syn RSS 0.91
Syn Subscribe
CC Licensed
Geo URL
With Radio
Introduction
In Higher Order Programming in Javascript I discussed the various ways of using functions as values. One particular trick in that document caught the attention of Dan Shappir, who pointed out to me: "your technique shows how JavaScript supported delegates all along, so this is not some great C#/.NET invention." While searching for some more information about these delegates, I found out that Microsoft has added them to Visual J++ too, invoking an interesting response from Sun, where it's discussed how delegates can much better be implemented with Inner Classes. As this is aparently a hot issue in other languages, and because event handlers and callbacks are useful in webpages too, I decided to write a new article to discuss this.
The Trick
The problem is as follows: Methods use this to refer to the object it is a method of. But, when using a method as event handler or callback function, this does no longer point to that object. The trick is to use the closure like behaviour of functions, so that the method will always have access to it's object.
Let's look at an example: We want to use a method of an Alerter class as an event handler.

  1. function Alerter(text) {   this.text=text;   [b]var me=this;[/b]   this.invoke=function () {     alert([b]me[/b].text);   } }   var sayHi=new Alerter('Hello, world!'); div.attachEvent('onclick', sayHi.invoke);
复制代码


So, instead of using this, we use a variable me, that equals this when the invoke method is created. And, in contrast to this, me will keep refering to the correct Alerter object, even when it's passed as a function to the attachEvent method of an HTML element.
Higher Order Programming again
window.setTimeout is an often used function for dynamic webpages. It waits for a given amount of time, and then calls a callback function. The above defined sayHi function can be used as a callback function: setTimeout(sayHi.invoke,2000) will show an alert box after 2 seconds. But what if we want to be extra cool and show 2 alert boxes after those 2 seconds? Then we'd have to create a new function that calls both Alerter objects:

  1. var sayHi=new Alerter('Hello, world!');   var sayBye=new Alerter('Bye, world!'); setTimeout(function() {sayHi.invoke();sayBye.invoke();},2000);
复制代码


A nice feature of Microsoft's delegates is that you can create a single composite deligate from several delegates. It looks less messy than inserting an anonymous function. Let's do that in Javascript too, by extending the function prototype.

  1. Function.prototype.andThen=function(g) {   var f=this;   return function() {     f();g();   } };
复制代码


Now we can write:

  1. setTimeout((sayHi.invoke).andThen(sayBye.invoke),2000);
复制代码


Several callbacks
With the andThen method, it becomes very easy to create an object that allows several other objects to register callbacks.

  1. function Manager() {   this.callback=function () {}; // do nothing   this.registerCallback=function(callbackFunction) {     this.callback=(this.callback).andThen(callbackFunction);   } }   var manager=new Manager(); manager.registerCallback(sayHi.invoke); manager.registerCallback(sayBye.invoke); manager.callback();
复制代码


Conclusion
With a simple technique event handlers and callback functions become a lot more interesting in Javascript. As Dan Shappir pointed this out to me, just this morning (after which I started to write the article), I can't wait to try more of this. I hope you can't too, and if you've got something to show, don't hesitate to contact me.


转载自:http://w3future.com/html/stories/callbacks.xml

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
2 [报告]
发表于 2005-12-15 21:55 |只看该作者

Higher Order Programming

Higher Order Programming


Higher Order Programming - article
In Javascript
Required knowledge
You'll have to know how to program object oriented with Javascript. Read the articles at Webreference (links at the left of the article) to catch up on that.
Last Update
10/16/2005; 1:23:45 AM
Try XHTML 2.0
Src XHTML 2.0
RDF Metadata
Site Search
Site Colors
Site E-mail Me
Syn Atom 1.0
Syn RSS 0.91
Syn Subscribe
CC Licensed
Geo URL
With Radio
Introduction
Higher Order Programming is the ability to use functions as values. So you can pass functions as arguments to other functions and functions can be the return value of other functions. This style of programming is mostly used in functional programming, but it can also be very useful in 'regular' object oriented programming. A good example of this is the Ruby Scripting Language, which combines all the advantages of pure object oriented programming and higher order programming. Sadly, Ruby is not supported by any browser, so it cannot be used for websites. We are lucky however that Javascript is available in every browser, and that Javascript is so flexible that it can be extended to make higher order programming a helpful tool in scripting webpages.
The sort method
Most people will know Javascript only as a scripting language that makes image switching and annoying popup windows possible. However the Javascript implementations hint at the more advanced programming possibilities through the sort Method of arrays. In it's simple form sort() will just sort the array: The code document.write([2,3,1,4].sort()) will write "1,2,3,4". But the sort method can do more. It allows a compare function as an optional argument. That's higher order programming right there. Suppose we have an array of objects. Each object has a date property, and we want to sort the objects by their date value:

  1. arrayOfObjects.sort(   function (x,y) {     return x.date-y.date;   } );
复制代码


The compare function is called regularly during sorting. It must return a negative value when x comes before y, zero when the are equal and a possitive value when x comes after y. This is exactly what substraction does for numbers and dates, for strings you can just use < and >.
Generating HTML
Using functions as arguments
If you have generated HTML from arrays before, this code will look familiar:

  1. var s=''; for (var i=0;i<arr.length;i++) {   var item=arr[i];   s+=[i]...generate some HTML...[/i] } document.write(s);
复制代码


We will now create a reduce method, that will make this a bit more readable, and make the code more modular. The above code will then look like this:

  1. function prettyTemplate(item) {   return [i]...generate some HTML...[/i] } document.write(arr.reduce(prettyTemplate));
复制代码


To create the reduce method, we can use much of the previous example. We'll extend the array prototype, so all arrays will have the reduce method available:

  1. Array.prototype.reduce=function(templateFunction) {   var l=this.length;   var s='';   for (var i=0;i<l;i++) s+=templateFunction(this[i]);   return s; }
复制代码


Using a function as return value
The template function will often be simple: It will just wrap each item in the array with one HTML element. F.e. when creating a table, the template function won't do much more than: return '<TD>'+item+'</TD>';. Let's create a function that generates these simple element wrappers:

  1. function wrap(tag) {   var stag='<'+tag+'>';   var etag='</'+tag.replace(/s.*/,'')+'>';   return function(x) {     return stag+x+etag;   } }     // examples:   document.write(wrap('B')('This is bold.')); var B=wrap('B'); document.write(B('This is bold too.'));   document.write(   '<TABLE><TR>'+     arr.reduce(wrap('TD class="small"'))+   '</TR></TABLE>' );
复制代码


In the first example you can see that you can immediately call the returned function, which results in a somewhat unusual syntax of two argument lists next to eachother. There's another special thing happening here: the returned function referes to the stag and etag variables. That this works outside of the wrap function is because of the closure like behaviour of functions in Javascript. When a function is defined, it stores a pointer to the current scope. This scope is restored when the function is called.
Using functions as objects
In the last example, an array is converted to a table, each item in the array is wrapped with a <TD> element. If we want a vertical table layout, instead of horizontal, each item must be wrapped with both a <TR> element and a <TD> element. So we must create a new function again:

  1. var TABLE=wrap('TABLE');var TR=wrap('TR');var TD=wrap('TD'); document.write(TABLE(arr.reduce(   function (item) {     return TR(TD(item));   } )));
复制代码


TR(TD(item)) is like function composition, written as 'TR o TD', and pronounced as 'TR after TD'. So we'd like to write this as:

  1. document.write(TABLE(arr.reduce(TR.after(TD))));
复制代码


In Javascript functions are objects too, and they can also have methods. So we can extend the function prototype so that the after method is available to all functions.

  1. Function.prototype.after=function(g) {   var f=this;   return function(x) {     return f(g(x));   } }
复制代码


Using methods as functions
Update: Dan Shappir pointed out to me that is useful for event handlers and callback function too. Read more about that here.
When doing higher order programming in an object oriented language, you'd want to pass methods as arguments. But there's a problem. Let's make an element class with a wrap method:

  1. function element(tag) {   this.stag='<'+tag+'>';   this.etag='</'+tag.replace(/s.*/,'')+'>';   this.wrap=function(x) {     return this.stag+x+this.etag;   } }   P=new element('P'); // this works: document.write(P.wrap('This is a paragraph.')); // this fails: document.write(arr.reduce(P.wrap));
复制代码


Why does this fail? Because when P.wrap is passed to the reduce function, only the function is passed, where this has a different meaning. But there's a little trick that makes method passing work:

  1. function element(tag) {   this.stag='<'+tag+'>';   this.etag='</'+tag.replace(/s.*/,'')+'>';   var me=this;   this.wrap=function(x) {     return me.stag+x+me.etag;   } }   P=new element('P'); // this still works: document.write(P.wrap('This is a paragraph.')); // and now this works too: document.write(arr.reduce(P.wrap));
复制代码


It looks like it's the same, but me is just a variable where this has a special meaning to every function. Javascript will make sure the wrap method will still know what me points to, no matter where the method is used.
When should you use this?
Modularisation
When you have 2 (or several) functions that are almost the same except for a small part of the code, then you should consider to combine these functions into one. Replace the part that is different with a function call to a separate function. This function is passed to the new more general function as an argument.
Something different
When you've grown bored of writing for-loops (like I did), methods like reduce will be a welcome change in programming style. For me, higher order programming has made Javascript a lot more fun, and I hope you'll have fun with this too!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP