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将嵌套减少可以接受的范围。
加油!