`
JerryWang_SAP
  • 浏览: 1030510 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

使用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.

var  bigFunction  =  function()  {  // big logic console.log("big logic");  }

Of course if the big function is owned by you, you could directly append the enhancement, like below:

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:

bigFunction = bigFunction.after(  function()  { console.log("our own logic");  });

Now 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( valu
0
1
分享到:
评论

相关推荐

    prototype.js 以及 找到的 相关使用详细说明

    实践中,可以尝试用Prototype.js重构一些传统的JavaScript代码,体验其带来的便利。同时,结合实际的网页应用,比如构建动态表格、实现无刷新更新等,可以更好地掌握Prototype.js的用法。 总的来说,Prototype.js是...

    ReSharper.ReJS:JavaScript 重构

    JavaScript 重构 ###Available 快速修复####Convert 对象的属性访问从引用形式到索引形式,反之亦然 例子 var z = x . y ; // =&gt; var z = x['y']; var z = x [ 'y' ] ; // =&gt; var z = x.y; ####Detect 函数调用...

    seajs培训 重构代码

    在"train1108"这个压缩包中,很可能包含了使用Sea.js进行代码重构的示例和教程,你可以通过学习这些资源进一步理解如何将传统JavaScript代码转换为模块化结构,以及如何利用Sea.js提高开发效率和代码质量。...

    javascript Function

    ### JavaScript中的Function应用详解 #### 一、基本概念与用法 在JavaScript中,`Function` 是一个内置对象,它允许我们创建动态的函数。它不仅支持传统的函数声明,还能用于构建复杂的对象模型和实现一些高级特性...

    JavaScript风格指南.zip

    通过阅读"说明.txt"和解压"javascript_master.zip"中的示例,你可以进一步巩固这些概念,并发现更多关于代码组织、代码重构以及最佳实践的细节。遵循JavaScript风格指南,不仅能够提高代码质量,还能提升团队协作...

    扩展javascript的Date方法实现代码(prototype)

    最近项目的部分功能正在重构,前端也基本上推翻了原来的设计,在之前半年的积累上有了新的方案。... 代码如下: //将指定的毫秒数加到此实例的值上 Date.prototype.addMilliseconds = function (value) { var milliseco

    收集JavaScript代码的运行时类型信息

    总结来说,收集JavaScript代码的运行时类型信息涉及使用`typeof`、`instanceof`、`Object.prototype.toString.call()`等方法,以及利用开发者工具和静态类型检查工具。理解这些工具和技巧,能够帮助我们编写更健壮、...

    JavaScript插件化开发教程(六)

    在给定的代码段中,我们看到了一个使用构造函数和原型的方法来定义一个对象及其行为的例子。例如: ```javascript function ItemSelector(elem, opts){ this.elem = elem; this.opts = opts; }; var ISProto = ...

    JavaScript.Patterns

    本文介绍了JavaScript中的一些常用设计模式,包括单例模式、工厂模式、抽象工厂模式、适配器模式、装饰者模式、策略模式以及观察者模式。通过这些设计模式的应用,可以有效地提高代码的质量和可维护性,同时也能够...

    策略模式1

    为了解决这些问题,我们可以使用策略模式重构代码。首先,我们将每个验证规则封装成一个独立的类,这些类通常称为策略类。例如,我们可以创建`IsNonEmptyValidator`, `IsNumberValidator`和`IsAlphaNumValidator`等...

    编写可维护面向对象的JavaScript代码[翻译]

    在JavaScript中,虽然传统意义上没有类的概念,但它支持基于原型(Prototype)的继承机制,也支持使用ES6引入的类语法来更好地支持面向对象编程。 面向对象编程具有几个核心概念,包括封装(Encapsulation)、继承...

    2014年4月阿里前端实习线上试题

    在JavaScript中,可以使用`Array.prototype.sort()`函数,传入一个比较函数作为参数。比较函数接收两个元素作为参数,如果第一个元素应该排在前面则返回负数,如果第二个元素应该排在前面则返回正数,相等则返回0。...

    javascript面向对象

    4. **重构**:持续优化代码结构,提高代码质量和可维护性。 通过以上介绍,我们可以了解到,虽然JavaScript不是一开始就设计为面向对象的语言,但通过灵活运用其特性,可以有效地实现面向对象的编程模式。这对于...

    bindings:将功能绑定到dom

    "更实际的例子"意味着可能在压缩包文件中有实际的JavaScript代码示例,用于演示如何将函数绑定到DOM元素,以及如何处理`Function.name`在不兼容浏览器中的问题。在实际应用中,我们可能会用到如`addEventListener`...

    javascript写类方式之九

    在学习和分析这些代码时,我们可以理解它们的工作原理,学习如何优化和重构代码,以提高代码的可读性和可维护性。 总的来说,JavaScript的类实现方式多样,适应了不同场景的需求。无论是老式的函数构造器和原型链,...

    javascript之学会吝啬 精简代码

    javascript 之吝啬精简代码 javascript 之吝啬精简代码是指在前端开发中,学习如何吝啬自己的代码,写出更加简洁高效的代码。下面是相关知识点的总结: 一、吝啬代码 吝啬代码是指在编写代码时,尽量少用代码实现...

    javascript如何实现create方法

    例如,一些库或框架可能使用`create`方法来实现继承机制,或者在使用类(class)之前,某些旧的JavaScript代码可能使用`create`方法来模拟类的行为。 需要注意的是,尽管`create`方法非常强大,但在实际的项目开发...

    reflection:只是玩弄esprima和JavaScript中的反射。

    在"reflection:只是玩弄esprima和JavaScript中的反射"项目中,作者可能探索了如何使用Esprima解析JavaScript代码,然后通过反射技术对代码进行分析、修改和操作。这可能包括动态创建和调用函数、检查和修改对象的...

    经典向上滚动且停顿代码

    - 对JavaScript代码进行重构,使其更加模块化和可维护。 以上就是关于“经典向上滚动且停顿代码”的详细知识点介绍。通过学习这段代码,不仅能够帮助开发者掌握基本的前端技术应用,还能够在实际项目中灵活运用这些...

Global site tag (gtag.js) - Google Analytics