使用JavaScript Function.prototype进行代码重构的一些例子-阿里云开发者社区

开发者社区> -开发者助手-> 正文

使用JavaScript Function.prototype进行代码重构的一些例子

简介: 使用JavaScript Function.prototype进行代码重构的一些例子
+关注继续查看

Example1 – how to enhance a big / complex function with your own logic

Suppose there is already a big function with huge logic, and you have the task to enhance it by appending your own logic to its end.

image.png


var  bigFunction  =  function()  {  // big logic console.log("big logic");  // append our own enhancement directly console.log("our own enhancement");  }

Another approach, if you would not like to touch the existing one, is to use a temporary variable to store the old bigFunction:


var _old = bigFunction;  bigFunction  =  function()  {  if  ( _old )  {  _old();  } console.log("our own enhancement");  }  bigFunction();  // After it is executed, console will print out

A Better Solution

We add a new function in Function.prototype:


Function.prototype.after  =  function( func ){  var _self =  this;  return  function()  {  var ret =  _self.apply(  this, arguments );  if  ( ret ===  false  )  {  return  false;  }  func.apply(  this, arguments);  return ret;  }  }

This after function returns a new function, which will first call the original function, and then call the subsequent function passed in via variable “func” if the original function execution is successfully ( ret != false ).


Then just construct a new function using after function:

image.pngNow when bigFunction() is executed, we get the same printout. With this approach, the temporary variable is avoided.


Example 2 – Write performance measurement code without polluting your productive code

Suppose in your application you have to create mass div node. You need to measure the creation performance. The most straightforward way is to get timestamp before and after creation. In order to get timestamp you cannot avoid to pollute your productive code with two “new Date()” ( or any other way for time measurement in JavaScript ) as below.


var  append_doms  =  function()  {  var d =  new  Date();  // dirty code - nothing to do with application logic!!!  for(  var i =  0; i <  100000; i++)  {  var div = document.createElement(  "div"); document.body.appendChild(div);  }  // dirty code - nothing to do with application logic!!! console.log(" time consumed: "  +  (  new  Date()  - d));  };

A Better Solution

Using the idea of the first example, we create another method before in Function.prototype, which has similar design as Function.prototype.after:


Function.prototype.before  =  function( func)  {  var _self =  this;  return  function()  {  if  (  func.apply(  this, arguments )  ===  false  )  {  return  false;  }  return  _self.apply(  this.arguments);  }  }

With this approach, our productive code is clean – not any time measurement code there.


var  append_doms  =  function()  {  for(  var i =  0; i <  100000; i++)  {  var div = document.createElement(  "div"); document.body.appendChild(div);  }  };

And we wrap the original function with before and after function we defined in Function.prototype:


var  log_time  =  function( func, log_name)  {  return func =  (  function()  {  var d;  return func.before(  function(){ d =  new  Date();  }).after(  function(){ console.log( log_name +  (  new  Date()  - d));  });  })();  };

Now we get a new function log_time which is dedicatedly used for performance measurement. This new function actually consists of three parts:


(1) an anonymous function with body “d = new Date();”, chained by Function.prototype.before.


(2) the original append_doms


(3) an anonymous function with body “console.log( log_name + ( new Date() – d)); “, chained by Function.prototype.after.


We can elegantly call it via one line of code below to achieve the performance measurement.


log_time(append_doms, "consumed time: ")();


AOP in Java

Update on 2016-07-29: In Java it could be done elegantly via Spring framework. Please find more detail from this blog: [An example to explain why we need AOP – Aspect Oriented Programming](https://blogs.sap.com/?p=145576) .


Example 3 – Replace lots of IF-ELSE with Design Pattern “Chain of Responsibility”

Suppose I am responsible for developing a file upload function and the upload could be finished by various approach if each feature is supported by client side. The priority is listed below:


// Priority: ActiveX > HTML5 > Flash > Form(default)


If means for example, if ActiveX is supported by client’s browser, it should be used. The default is upload via form, if all previous tries have failed


function  isActiveXSupported(){  //...  return  false;  }  function  isHTML5Supported(){  //...  return  true;  }  function  isFlashSupported(){  //...  return  false;  }

The codes above just simulate the situation that HTML5 upload should be used, since its preceding attempt, isActiveXSupported, returns false. In order to get the proper upload service, we have to code lots of tedious IF-ELSE evaluation:



var uploadAPI;  if  (  isActiveXSupported())  {  // lots of initialization work uploadAPI =  {  "name":  "ActiveX"};  }  else  if(  isHTML5Supported())  {  // lots of initialization work uploadAPI =  {  "name":  "HTML5"};  }  else  if(  isFlashSupported())  {  // lots of initialization work uploadAPI =  {  "name":  "Flash"};  }  else  {  // lots of initialization work uploadAPI =  {  "name":  "Form"};  } console.log(uploadAPI);  // HTML5 service is got

A Better Solution

We do some minor change on Function.prototype.after:


Function.prototype.after  =  function( func ){  var _self =  this;  return  function()  {  var ret =  _self.apply(  this, arguments );  if  ( ret )  {  return ret;  }  return  func.apply(  this, arguments);  }  }

Now if the execution of original function is successfully ( returns true ), we terminate the function chain, that is, we don’t pass the responsibility chain to its subsequent function passed via func.


With this approach, there is no more IF-ELSE evaluation. In fact, now we spread the evaluation into the dedicated initialization function of each API:


var  getActiveX  =  function()  {  try  {  // lots of initialization work  return  {  "name":  "ActiveX"};  }  catch  (e)  {  // user broswer does not support ActiveX  return  null;  }  }  var  getHTML5  =  function()  {  try  {  // lots of initialization work  return  {  "name":  "HTML5"};  }  catch  (e)  {  // user broswer does not support HTML5  return  null;  }  }  var  getFlash  =  function()  {  try  {  // lots of initialization work  return  {  "name":  "Flash"};  }  catch  (e)  {  // user broswer does not support Flash  return  null;  }  }  var  getForm  =  function()  {  return  {  "name":  "Form"};  } ```

Now in order to get appropriate API, we just use single line:

> var uploadAPI = getActiveX.after(getHTML5).after(getFlash).after(getForm)();

This design idea is actually the so called “Chain of Responsibility”. Simply speaking, the function in the beginning of chain ( in my example, it is getActiveX ) will analyze whether it is able to resolve the task. If yes, the whole statement returns, task is over. Otherwise, it simply delegate the task to the next node in the chain.

# Example 4 – eliminate lots of IF-ELSE in validity check via Strategy Design Pattern

For example, before we assemble the request payload to send OData request via OData API, we must perform various validity check on the user input. If you have a page with lots of UI elements, usually it will lead to lots of IF-ELSEIF-ELSEIF validity check code spread in your application.

```javascript

var  send  =  function()  {  var value = input.value;  if( value.length ===  ''  )  {  return  false;  }  else  if( value.length >  MAX_LENGTH)  {  return  false;  }  ...  // LOTS OF other rules to be checked  else  {  // all check passes, now ready to call OData API  }  }

A Better Solution

Instead of directly coding all those validity checks in the application, we can first put the rules in a JavaScript object (so called “Strategy” in Design Pattern ):



var valid_rules =  {  not_empty:  function( value )  {  return value.length !==  '';  },  max_length:  function( value )  {  return value.length <=  MAX_LENGTH  ;  }  }

With strategy ready, now we can simply write the validity check function in a generic way. It doesn’t know any detail about validity rules, but simply scan rules configured in strategy object one by one. If any check fails, the whole function will return false – check not pass.


var  valid_check  =  function()  {  for(  var i in valid_rules )  {  if  ( vali_rules[i].apply(  this, arguments)  ===  false  )  {  return  false;  }  }  }

Finally the send function could be reduced as:


var  send  =  function( value )  {  if  (  valid_check( value )  ===  false  )  {  return;  }  // all check passes, now ready to call OData API  }

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10012 0
JavaScript进阶之路——认识和使用Promise,重构你的Js代码
  一转眼,这2015年上半年就过去了,差不多一个月没有写博客了,"罪过罪过"啊~~。进入了七月份,也就意味着我们上半年苦逼的单身生活结束了,从此刻起,我们要打起十二分的精神,开始下半年的单身生活。大家一起加油~~   一直以来,JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深入人心。
886 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2958 0
热点浅谈:与传统IT开发相比,低代码平台有何优势?
传统的瀑布式应用程序开发过程,需要许多具有高度专业化角色的人参与。例如,该过程需要业务分析师创建功能需求,技术分析师将这些需求转化为技术规范,数据库管理员创建数据库并设计数据库模式,UX/用户界面开发人员创建线框和设计,许多开发人员编写应用程序,将所有部分结合在一起。
16 0
使用dom breakpoint找到修改属性的javascript代码
使用dom breakpoint找到修改属性的javascript代码
4 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10880 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13811 0
你不得不使用的XML代码生成器,那就是XmlFactory
这个XML Factory工具很好。如果你有现成的Xml文档,那么大部分情况下你不需要手工写代码来处理Xml与实体对象间的转换。 博客园这位兄弟有详细的使用情况:http://www.cnblogs.com/rada2002/archive/2011/12/15/2288171.html
551 0
2450
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载