打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Higher Order Programming

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:

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:

var s=‘‘;for (var i=0;i<arr.length;i++) {  var item=arr[i];  s+=...generate some HTML...}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:

function prettyTemplate(item) {  return ...generate some HTML...}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:

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:

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:

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:

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.

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:

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:

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.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
解密 JavaScript 中的 this
20个JS优化代码技巧
COS上传图片 Web 端直传实践
js 随机取数组元素
JavaScript控制下拉框(Select)
11种JavaScript生成1到100的数组的方式汇总
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服