现在的位置: 首页 > Tools > highcharts > 正文
Highcharts源码分析之wrap函数
2015年07月28日 highcharts, javascript, underscore ⁄ 共 3659字 评论数 2 ⁄ 被围观 5,734 views+
文章目录
[隐藏]

今天在看Highcharts源码的时候,发现一个比较有意思的函数wrap,代码只有8行,不过却实现了对函数功能进行扩展的能力,作者javascript功底略见一斑,本篇文章做下记录和分析。

首先来看一个问题,众所周知的parseInt函数,其实有两个入参,我们在使用的时候往往不用第二个入参。这个时候parseInt(str),如果str以"0x"开头,则认为是十六进制;如果是以"0"开头,则认为是八进制。但是现实情况呢,在复杂的业务代码中有时候不可避免会出现"099","0AA"这样的字符串,他们显然不是八进制,而是十进制和十六进制。

parseInt("099"),在IE6~8下都返回0,其它浏览器,以及版本高于8的浏览则能正确返回99,可见高版本浏览器要智能一些;

parseInt("0AA"),几乎在所有浏览器下,都返回0,这说明浏览器依旧是不够智能。

我们如何来完善这个问题呢,当然了,我们可以自己重写parseInt,覆盖原生的parseInt。而Haigcharts却用8行代码封装了这样一个用于扩展函数功能的小工具——wrap函数:

  1. var wrap = Highcharts.wrap = function (obj, method, func) {
  2.     // 备份原函数
  3.     var proceed = obj[method];
  4.     // 扩展原函数
  5.     obj[method] = function () {
  6.         // 拷贝一份实参
  7.         var args = Array.prototype.slice.call(arguments);
  8.         // 将原函数的引用放到第一个入参
  9.         args.unshift(proceed);
  10.         // apply保持上下文调用func
  11.         return func.apply(this, args);
  12.     };
  13. };

下面我就用wrap来实现对parseInt函数的完善:

  1. wrap(window,'parseInt',function(proceed, str, scale){
  2.     if(typeof str === "number"return proceed.call(this,str);
  3.     var hexChars = 'abcdef', decChars = '9';
  4.     var hasHex = false, hasDec = false;
  5.     if(!scale){
  6.         if(str.charAt(0)==='0'){
  7.             if(str.charAt(1).toLowerCase()==='x'){// 0x开头 十六进制
  8.                 return proceed.call(this,str,16);
  9.             }else{
  10.                 for(var i= 1,len=str.length; i<len; i++){
  11.                     var char = str.charAt(i).toLowerCase();
  12.                     if(hexChars.indexOf(char)>-1) hasHex = true;
  13.                     if(decChars.indexOf(char)>-1) hasDec = true;
  14.                 }
  15.                 if(hasHex){// 0开头,但是包含ABCDEF等字符,则认为是十六进制
  16.                     return proceed.call(this,str,16);
  17.                 }else if(hasDec){// 0开头,但是包含9,认为是十进制
  18.                     return proceed.call(this,str,10);
  19.                 }else{// 这才是真正的八进制
  20.                     return proceed.call(this,str,8);
  21.                 }
  22.             }
  23.         }
  24.         return proceed.call(this,str,10);
  25.     }
  26. });
  27. console.log(parseInt("0777"));// 511
  28. console.log(parseInt("090"));// 90
  29. console.log(parseInt("0AA"));// 170
  30. console.log(parseInt(12345));// 12345

其它类库的实现

Underscore的实现

在其它一些实用的js库里面也有类似函数的封装,比较典型的是Undescore.js,代码甚至比Highcharts的实现还要简洁一行,实现逻辑基本一致,我们来看看:

  1. _.wrap = function(func, wrapper) {
  2.     return function() {
  3.         var args = [func];
  4.         //这个地方用了一个小技巧,把func放到数组第一个元素,不过push方法能自动把arguments参数转成数组元素,这个小技巧我也是才知道
  5.         Array.prototype.push.apply(args, arguments);
  6.         return wrapper.apply(this, args);
  7.     };
  8. };

要注意的是Underscore的实现跟Highcharts是有区别的,Highcharts是直接替换掉了原函数,而Underscore并没有替换掉原函数,必须要重新赋值一次以覆盖原函数,比如:

  1. // 这是Underscore里面的wrap函数,我把它拿出来了
  2. function wrap(func, wrapper) {
  3.     return function() {
  4.         var args = [func];
  5.         //这个地方用了一个小技巧,把func放到数组第一个元素,不过push方法能自动把arguments参数转成数组元素,这个小技巧我也是才知道
  6.         Array.prototype.push.apply(args, arguments);
  7.         //apply this是为了保持原函数的上下文
  8.         return wrapper.apply(this, args);
  9.     };
  10. }
  11. // 一个对象,算是个人吧
  12. var person = {
  13.     age: 33,
  14.     // 本人今年33
  15.     name: "世纪之光",
  16.     //江湖人称 世纪之光
  17.     marry: false,
  18.     //依旧是一条老光棍
  19.     // 生活虽然不顺,但是我依旧乐观,见人要有礼貌
  20.     hello: function(who) {
  21.         console.log("hello " + who);
  22.         return this.name + " says: Hello " + who;
  23.     }
  24. }
  25. // 必须要用wrap函数返回的匿名函数覆盖原来的定义
  26. person.hello = wrap(person.hello,
  27. function(func, name, more) {
  28.     return func(name) + " " + more;
  29. });
  30. var str = person.hello("kitty""have dinner?");
  31. console.log(str);
lowpro.jquery.js中的实现
  1. $.extend({
  2.     // 类似于Underscore里面的bind函数,让this始终指向上下文scope
  3.     bind: function(func, scope) {
  4.         return function() {
  5.             return func.apply(scope, $.makeArray(arguments));
  6.         }
  7.     },
  8.     wrap: function(func, wrapper) {
  9.         var __method = func;
  10.         return function() {
  11.             return wrapper.apply(this, [$.bind(__method, this)].concat($.makeArray(arguments)));
  12.         }
  13.     }
  14. };

目前有 2 条留言 其中:访客:1 条, 博主:0 条 引用: 1

  1. DEV_MZWJ : 2015年10月30日17:58:19  -49楼 @回复 回复

    好给力啊 😛

查看来自外部的引用: 1

给我留言

留言无头像?


×