chaojidan

导航

第七课:数值以及函数的扩展和修复

1.数值扩展和修复

toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。num必需,规定小数的位数,是 0 ~ 20 之间的值,包括 0 和 20,有些实现可以支持更大的数值范围。如果省略了该参数,将用 0 代替。返回 NumberObject 的字符串表示,不采用指数计数法,小数点后有固定的 num 位数字。如果必要,该数字会被舍入,也可以用 0 补足,以便它达到指定的长度。如果 num 大于 le+21,则该方法只调用 NumberObject.toString(),返回采用指数计数法表示的字符串。

但在有些浏览器下不会这样干,于是修复:

if(0.9.toFixed(0) !=='1'){

  Number.prototype.toFixed = function(n){    

    var power = Math.pow(10,n);    //Math.pow(x,y),返回 x 的 y 次幂的值

    var fixed = (Math.round(this*power) / power).toString();    //把一个数字舍入为最接近的整数。比如:0.5->1,0.4->0

    if(n == 0)  return fixed;      //当n等于0时,就直接调用round方法,把num四舍五入为最接近num的整数

    if(fixed.indexOf('.')<0)  fixed + = '.';        //如果是整数,并且n>0,那么需要添加n位小数。所以先添加小数点.

    var padding = n+1 - (fixed.length - fixed.indexOf('.'));    //小数点后面必须有n个数字。没有就用0填补

    for(var i=0;i<padding;i++)  fixed + = '0';     //假设fixed为12.2,n为3,那么fixed.length=4,fixed.indexOf('.')=2,则padding = 4-2 =2;return 12.200

    return fixed;                                                   

  }

}

当javascript遇到一个数值时,它会首先尝试按照整数来处理该数值,如行得通,则把数值保存为31位的整数;如果该数值不能视为整数,或者超过31位的范围,则把数值保存为64位的IEEE754浮点数。

最大的Unicode值是1114111,最大的RGB颜色值是16777215(相当于#FFFFFF)。最大的10位数字是Math.pow(2,31)-1.最小的10位整数是-Math.pow(2,31)。

因此,js内部会以整数的形式保存所有Unicode值和RGB颜色。

我们尽量在前端只处理以整数形式保存的数字,大数和小数的操作尽量交给后台处理,实在避免不了,就用专业的库来处理。

2.函数的扩展与修复

bind函数:改变函数执行的上下文。低版本浏览器不支持,需要扩展。

Function.prototype.bind = function(context){

  if(arguments.length < 2 && context == undefined){  

    //当传入的参数1个或者0个,并且第一个参数为undefined时(其实就是没传入context,或者传入一个undefined的context),就返回this,也就是函数本身

    return this;      //当方法say.bind(undefined,chaojidan),这种情况下,不会返回this,而是把chaojidan这个参数保存下来,之后会作为参数传到方法say中去。

  }

  var _method = this,args = [].slice.call(arguments,1);

  return function(){

    return _method.apply(context,args.concat.apply(args,arguments));      

      //此函数在传入的context上下文中执行。并且把bind传入的参数和函数本身传入的参数合并成一个数组传入函数中执行。

  }

}

这个方法用的最多的是在IE下添加事件时,this的指向问题。IE的API attachEvent在回调中的this指向window.

var addEvent = document.addEventListener ? functon(el,type,fn,capture){  

    el.addEventListener(type,fn,capture)  ;

  } : function(el,type,fn){

    el.attachEvent("on"+type, fn.bind(el));     //把this指向了el元素

  }

apply方法第二个参数一定要是数组或者arguments这样的类数组(jQuery对象{0:"0",1:"1",length:2}也是类数组)。(NodeList这样的传进去在有些浏览器会出问题,因此jQuery中是使用merge来处理数组的合并,而不是使用Array.prototype.push.apply来处理,当然slice,concat这类的数组方法在有些浏览器下也不能很好的处理NodeList)。

hasOwnProperty判断是否是对象的实例属性,而不是原型属性。

bind方法着重于作用域的劫持,改变方法执行时的上下文。

curry 函数柯有化在于参数的不断补充,它可以给你再一次传参的机会,这样你就可以在内部判定参数的个数,决定是否继续返回函数还是结果。这在设计计算器的连续运算上非常有用。举个例子:function curry (fn){   

          function inner(len,arg){  

            if(len<=0)  return fn.apply(null,arg);  

            return function(){  return inner(len-arguments.length,arg.concat(Array.apply([],arguments)))  }  

          }   

          return inner(fn.length,[]); 

       }

function sum(a,b,c,d){  return a+b+c+d;  }

curry(sum)('a')()('b','c')('d')       //return 'abcd';

这种自身调用自身来补全参数的,叫做self-curry或者recurry。

与curry相似的partial。curry的不足是参数总是通过push的方式来补全,而partial则是在定义时所有参数已经都有了,但某些位置上的参数只是一个占位符,我们在接下来的传参只是替换掉它们。

Function.prototype.partial = function(){

  var fn = this, args = Array.prototype.slice.call(arguments);

  return function(){

    var arg = 0;

    for(var i=0;i<args.length&&arg<arguments;i++ ){

      if(args[i] == undefined){

        args[i] = arguments[arg++];

      }

    }

    return fn.apply(this,args);

  }

}

这里是使用undefined作为占位符。

比如:var delay = setTimeout.partial(undefined,10);     ->  fn = setTimeout

delay(function(){});      //执行时,会先执行for循环,把partial中的参数遍历,如果有undefined,就用delay中的参数代替,因此这里会用function代替undefined。这时return setTimeout.apply(this,[function,10])。

对于占位符,我们可以使用一个纯空对象:

var _ = Object.create(null);      //纯空对象没有原型,没有toString,valueOf等继承自Object的方法。

另外一种实现方法:

function partial(fn){

  var A = [].slice.call(arguments,1);     //数组化

  return A.length < 1? fn : function(){

    var a = Array.apply([],arguments);    //数组化

    var c = A.concat();       //复制一份

    for(var i =0;i<c.length;i++)  if(c[i] === _)  c[i] = a.shift();

    return fn.apply(this,c.concat(a));    

  }

}

function test(a,b,c,d){  return a+b+c+d;  }

var fn = partial(test, 1, _,2,_);        //这里的意思就是,方法test需要传入4个参数,目前只传入了两个。其他两个用_来占位。

fn(4,5)      //再传入两个参数,传参结果是(1,4,2,5),然后返回执行test的方法。

curry和partial的应用场景比较少,主要使用在异步上。比如:Ajax的异步函数回调嵌套问题,就可以使用curry将嵌套减少可以接受的范围。

 

 

加油!

 

posted on 2014-12-01 15:16  chaojidan  阅读(726)  评论(0编辑  收藏  举报