标签 js 下的文章

今天在写一个倒计时的时候,突然想起一个问题,“对于 js 的小数取整,那种方法效率最高呢?”

然后我就把我能想到的取整的方法做了一下测试,大概是这个样子

Math.floor(-100/3)
parseInt(-100/3)
~~(-100/3)
(-100/3 >> 0)
(-100/3 | 0)
( -100 - (-100%3) ) / 3

然后我把每种方法跑了 10^7 次,取了一下平均值,然后发现:

  • Math.floor 耗时 0.0000197 ms
  • parseInt 耗时 0.0000225 ms
  • ~~(-100/3)(-100/3 >> 0)(-100/3 | 0) 三个耗时基本相同,大概都是 0.0000029ms 的样子
  • ( -100 - (-100%3) ) / 3 耗时 0.0000155ms

基本可以看出,三个位运算的方法耗时最少,而且少很多,那么是不是我们就可以使用这三种方法了呢?

在说答案之前,我们先来看看他们都干了什么吧

首先,位运算为什么能取整?

因为 js 是弱类型的语言,在对一个数进行位运算的时候,实际上是先对其进行 ToInt32 操作,转换成整数,然后再进行位运算。那么这里就有一个问题,原来的数被 ToInt32 之后,会变成一个 32 位长的整数,多余的部分会被截掉,当然,还包含一个符号位,那么也就是说,我们实际有效的数字只有 31 位,也就是 2147483647-2147483648

所以,当你的数字超过这个范围的时候,使用位运算的时候,就会计算出一些很奇怪的数字,其实因为 ToInt32 的时候被截掉了

那么现在来看答案就比较明显了, 如果你的数字会超过 32 位,那么就不能使用位运算。

然后再来看看 Math.floor,它是向下取整,也就是说,如果你的数字是负数的话,向下取整就是这样

Math.floor(-1.5)   // -2

剩下的两个 parseInt(-100/3) 比较稳定,功能也强大,支持不同进制转换,但是耗时也最长。

( -100 - (-100%3) ) / 3 这一坨就不说了,速度还可以,但是不易维护,如果不是情况特殊的话,我应该不会用这种办法吧

最后,就看你的实际情况来选择喽~

今天就到这里啦,如果有什么不对的地方,请留言告诉我哈~

大家晚安~

故事的起因源于群中有人提的一个问题:

a(1)=1;

a(1)(2)=3;

a(1)(2)(3)=6;

还原出函数a

好吧,我刚看到这个题目的时候,第一反应就是递归的闭包,然后就写了下面这一版:

var a = function(num){
    this.sum = this.sum || 0;
    if(num){
        this.sum += num;
        return a;
    }
    var result = this.sum;
    delete this.sum;
    return result;
}

但是这样的执行是这样的:

a(1)();    // 1

a(1)(2)(); // 3

和题目要求的不一样,而且还有sum没有及时重置,所以,这个办法不行

然后想了一会儿没想出好办法,就去求助原公司大牛。果然大牛就是不一样,给出了下面这个解决方案

function a(x){
    var list = [];
    list.push(x);
    var y = function(xx){
        list.push(xx);
        return y;
    };
    y.valueOf = function(){
        return list.reduce(function(a,b){return a+b;},0);
    }
    return y;
}

利用valueOf和闭包里的一个list做的,果断膜拜了一下

然后,后来有看到群里有人给出了这样的答案:

function a(num){
    function b(i){
        return a(num+i);
    }
    b.toString = function(){
        return num;
    };
    return b;
}

也是可以的,然后就比较好奇,这个valueOf和toString是怎样被执行的呢?

果断去补习了一下基础知识:

对于所有的js对象(除了null以外),都有valueOf和toString方法,这是为了更方便的对一个对象进行值的操作

比如说我们要比较两个object的大小的时候,就可以定义一下它的valueOf方法或者toString來比较大小,那么到底什么时候会调用这两个方法呢?

来看一个小测试:

    var bbb = {
        i: 10,
        toString: function() {
          console.log('toString');
          return this.i;
        },
        valueOf: function() {
          console.log('valueOf');
          return this.i;
        }
      }
      alert(bbb);          // 10 toString
      alert(+bbb);         // 10 valueOf
      alert(''+bbb);       // 10 valueOf
      alert(String(bbb));  // 10 toString
      alert(Number(bbb));  // 10  valueOf
      alert(bbb == '10');  // true valueOf
      alert(bbb === '10'); // false

貌似是跟字符串有关的会调用toString,而根数字有关的会调用valueOf方法,但是,我们发现(''+bbb)这个调用的是valueOf,而最后的===则什么都没有调用,那我们再试一下:

    var aa = {
        i: 10,
        toString: function() {
          console.log('toString');
          return this.i;
        }
      }
      alert(aa);         // 10 toString
      alert(+aa);        // 10 toString
      alert(''+aa);      // 10 toString
      alert(String(aa)); // 10 toString
      alert(Number(aa)); // 10 toString
      alert(aa == '10'); // true toString

很和谐的全是toString,再看看valueOf的:

    var bb = {
        i: 10,
        valueOf: function() {
          console.log('valueOf');
          return this.i;
        }
      }
      alert(bb);         // [object Object]
      alert(+bb);        // 10 valueOf
      alert(''+bb);      // 10 valueOf
      alert(String(bb)); // [object Object]
      alert(Number(bb)); // 10 valueOf
      alert(bb == '10'); // true valueOf

我们发现中间出现了[object Object],貌似是从Object那里继承过来的,我们把它去掉试试:

Object.prototype.toString = null;
var cc = {
    i: 10,
    valueOf: function() {
        console.log('valueOf');
        return this.i;
    }
}
alert(cc);         // 10 valueOf
alert(+cc);        // 10 valueOf
alert(''+cc);      // 10 valueOf
alert(String(cc)); // 10 valueOf
alert(Number(cc)); // 10 valueOf
alert(cc == '10'); // true valueOf

貌似和谐多了,那我们基本可以看到是这样的,如果只定义了toString方法,那么当遇到需要类型转换的时候,就会直接调用toString方法,然后如果只定义了valueOf方法的话,转换数字的时候会优先调用valueOf方法,然后在转换字符串的时候,如果实在没有toString可以调用才会用valueOf代替,对于有操作符的情况下(比如=),valueOf的优先级要比toString要高

感谢 小秦 同学纠正:当转换为数字类型的时候,如果 valueOf 返回的不是基础类型,才会调用 toString 方法

好了,那我们还有最后一个问题,(''+bbb),这个字符串拼接为什么是调用的valueOf呢?

这个问题应该是因为+操作符上,这里会有一个getValue操作,然后就调用valueOf方法了

嗯,好的,今天就这么多,有不对的地方欢迎指正~

话说这连天在修改原来老前辈留下来的js代码的时候,一不小心就遇到了一个蛋疼的问题,这里我就简单的抽象出一个模拟的栗子来,大概就是下面这个样子:


$("body").append("<textarea rows=6></textarea>");
console.log($("textarea").height());

差不多就是这样吧,so,console的结果是?


是红果果的0呀,有木有!! 后来就找公司大牛给解释一下,这货很淡定的在我的代码上加了这样一句:


setTimeout(function(){
    console.log($("textarea").height());
},0);

然后这个高度就毫无节操的跳出来了。。。


难道这个setTImeout(0)不就是立即执行的意思么?

蓝后捏,我就蛋疼的做了个实验:


console.log(1);
setTimeout(function(){
    console.log(2);
},0);
console.log(3);

so,结果捏?


嗯嗯,结果是 1 , 3 , 2  。。。。

好吧,这大概就可以解释一些东西了,当我在给body添加一个元素的之后,立刻去取这个元素的高度的时候,这时候js的这个添加的函数还没有完全执行完,虽然DOM中已经有了,但是浏览器也还没有渲染完成,所以这时候的取值是不正确的,而etTimeout之后,取值的操作就会被js放到下一个event loop中去执行,此时的添加和渲染DOM的操作都已经完成了,也就可以得到正确的结果了。。。

百度了一下,发现setTimeout(0)的应用还是挺广泛的,嗯嗯,看来以后要多多注意这些东西了~

嗯嗯,不过以上都是个人看法,如果有哪里理解有偏差的话,还是希望在大牛在留言里及时指出,嗯嗯~

好啦,就先到这吧,话说这几天好热,整个人都化了,木精神~ =.=!

嗯嗯,要是以后还发现其他的用处的话,应该还有后续滚动~ 嗯嗯,就这个样子~

今天晚上闲下来想去试试Jquery的animate函数,本来想随便写个看看效果,兰侯就去吃饭的,结果。。。。

先来看看刚开始写的吧


<html>
<head>
	<script src="http://code.jquery.com/jquery-1.9.1.min.js" language="Javascript"></script>
	<script>
		$(function(){
			$(".green").click(function(){
				$(this).animate({top : "300px"},300,"linear",function(){
					thi = $(this);
					setTimeout(function(){
						thi.animate({top : "100px"},300);
					},1000);
				});
			});
		})
	</script>
	<style>
		.green{
			position : relative;
			float : left;
			top : 100px;
			left : 200px;
			margin : 10px;
			height : 100px;
			width : 100px;
			background-color : green;
		}
	</style>
</head>
<body>
	<div class="green"></div>
</body>
</html>

特别简单的代码,就是看看animate的效果,木有其他的想法,运行起来也木有问题。。。


本来这样就行了嘛,大家都好好的,结果,好吧,我手贱了,我多加了两个div,然后就。。。。


<html>
<head>
	<script src="http://code.jquery.com/jquery-1.9.1.min.js" language="Javascript"></script>
	<script>
		$(function(){
			$(".green").click(function(){
				$(this).animate({top : "300px"},300,"linear",function(){
					thi = $(this);
					thi.html("111");
					setTimeout(function(){
						thi.html("222");
						thi.animate({top : "100px"},300);
					},1000);
				});
			});
		})
	</script>
	<style>
		.green{
			position : relative;
			float : left;
			top : 100px;
			left : 200px;
			margin : 10px;
			height : 100px;
			width : 100px;
			background-color : green;
		}
	</style>
</head>
<body>
	<div class="green"></div>
	<div class="green"></div>
	<div class="green"></div>
</body>
</html>

额,当我快速将三个div都点击下去之后,好吧,我惊喜的发现只有最后一个起来了,而前两个都木有反应啊。。。。


蛋疼的人总是这样,然后就找原因呗,寻思了一下,感觉是因为setTimeout里使用的thi变量被覆盖的缘故。。。。

加了个输出后发现,应该就是这个的缘故,但是这是为什么呢?不是应该互不影响的么?

晚上睡觉的时候,我突然间想到一件事,没有用var声明的变量会变成全局变量,会不会是因为这个? 果断起来试了一下,问题就这么解决了。。。。

<html>
<head>
	<script src="http://code.jquery.com/jquery-1.9.1.min.js" language="Javascript"></script>
	<script>
		$(function(){
			$(".green").click(function(){
				$(this).animate({top : "300px"},300,"linear",function(){
					var thi = $(this);
					thi.html("111");
					setTimeout(function(){
						thi.html("222");
						thi.animate({top : "100px"},300);
					},1000);
				});
			});
		})
	</script>
	<style>
		.green{
			position : relative;
			float : left;
			top : 100px;
			left : 200px;
			margin : 10px;
			height : 100px;
			width : 100px;
			background-color : green;
		}
	</style>
</head>
<body>
	<div class="green"></div>
	<div class="green"></div>
	<div class="green"></div>
</body>
</html>

好吧,一失足成千古恨,我就是一个失足少年呀~  现在觉的前端的编程规范真的很重要,以后要好好学习了。。。。


再兰候就是博客升了个级,貌似代码运行的插件不能用了,就先这样吧,最近也在准备弄VPS,博客这就先这样了,以后有时间了再好好弄弄。。。


就是这样。。。。 嗯嗯。。。。

<p>先声明一下,以下内容完全是个人经验的认识,并不保证正确,不要误导了还在茁壮成长的童鞋~</p>
<p> </p>
<p>此事说来话长,话说从盘古开天辟的时候。。。(这你妹也太长了点儿吧。。。)</p>
<p>=。=!  好吧好吧,其实就是昨天,办公室里的一个师哥在研究JS的闭包,然后就追溯到了JS变量的作用域链,并且最后弄出了这样一段代码:</p>
<p></p>

function makefunc(x) { 
  return function() { 
    return x; 
  }
}
var a = [makefunc(0), makefunc(1), makefunc(2)]; 
alert(a[0]()); 
alert(a[1]()); 
alert(a[2]());
<p></p> <p>结果就是分别弹出:0,1,2</p> <p> 这里就看出了,makefunc这个函数每次返回的函数都是相同的,但是,返回的函数的执行环境不同,也就是说这个函数所处的作用域链是不同的。。。</p> <p>当每次执行makefunc这个函数时,返回的是一个相同的匿名函数和这个匿名函数执行所需要的环境的综合体,这也就是传说中的闭包~ (主角终于登场了~)</p> <p> 那么我们就可以看出,数组a的每一个元素,其实都是一个function,用a[0]()这样的方式来执行它,从而得到了上面的结果,那当我们console.log出数组a的时候(不晓得用console.log出来的结果是不是足以证明一下的结论。。。。),我们发现它的每个元素里面都带有这个function执行时需要的变量x,也就是其实在a数组中的每个元素都是有他的完整的一套执行代码和运行空间,也就是闭包的真面目。。。。。</p> <p>那然后呢,我们俩个有继续巴拉巴拉。。。。。  说道作用域,又说道JS代码在执行时变量的存储和回收,于是就出现了下面这段代码:</p> <p></p>
var a = 10;
function b(){
    a = 3;
    function a(){}
}
b();
alert(a);
<p></p> <p>嘿嘿,看官们觉的这段代码的弹出结果是什么捏?</p> <p>function ? 不对~   3 ?  不对~  是10~!</p> <p>有木有,它竟然是10~! 你让函数里面那两个a情何以堪啊~</p> <p>那这是为什么捏? 其实还是比较简单的,是因为js在执行前,会先扫描一下全文,把用到的变量先在作用域的开头做一次声明,也就是我们看到的function a(),它的作用域是整个b函数,我们也知道</p> <p>function a(){} 和 var a = function(){} 是一样的,所以其实上面的代码在js的执行顺序是这样的</p> <p></p>
var a = 10;
function b(){
    var a ;
    a = 3;
    a = function(){};
}
b();
alert(a);
<p></p> <p>亲们,这下看出来了吧,函数里面的变量a在函数执行完后被回收,所以,下面的弹窗是显示的最开始的a的值。。。。。</p> <p>额,好吧,总觉得js的这个做法有些坑,但是还挺好玩的~</p> <p>那么,现在我们弄明白了js的作用域、作用域链以及传说中强大的闭包,那么我们就写个封装在闭包里的函数吧~</p> <p></p>
(function(){
  .........
})();
<p></p> <p>诶~ 诶~ 诶~ 等会儿~ function外面的那个小括号是干什么滴捏?</p> <p>封装闭包呀~封装闭包为什么要有一个小括号捏?话说没有那个小括号的话,function就不是闭包了?这个小括号在这里到底起了什么作用捏?(。。。。。  这。。。。  我还以为要结束了呢,怎么又来这么多问题?!)(所以才说是引发的“血案”啊~)</p> <p>好吧,那就再看看这个传说中的小括号吧~</p> <p>那么首先我们知道:</p> <p></p>
(fucntion(){alert(1);})();
<p></p> <p>这样写的话,里面的匿名function是会被执行的,那么当我们把小括号去掉呢?  </p> <p></p>
function(){alert(1);}();
好吧,我承认他执行不了。。。 = =!<p></p> <p>话说那去掉括号后要怎么样才会执行呢? 很明显给它加函数名调用嘛~</p> <p></p>
function a(){alert(1);};
a();
额,好吧,那话说我加上括号的话,再这样调用呢?<p></p> <p></p>
(function a(){alert(1)});
a();
哎呦喂~  竟然提示说a未定义~  这。。。。。<p></p> <p>那我们把里面的函数赋给一个全局变量会怎么样呢?</p> <p></p>
var a;
(a = function(){alert(1);});
a();
好吧,它执行了也就是说原来的代码在小括号作用完成后,里面的a被回收了。。。。<p></p> <p>经过翻阅资料,发现这里的小括号的作用是强制表达式运算,那么,也就是说它会让里面的表达式强制性进行一遍运算~</p> <p>那么,大概可以猜测上面的小括号的作用应该是类似于下面的代码</p> <p></p>
function (){
  return function (){alert(1);};
}
也就是说小括号运算结束后,把里面的a函数以匿名函数的方式返回回来,而返回的匿名函数实际上就是一个有执行代码和执行环境的一个闭包,这样,也就是实现了把方法封装到一个闭包里了。。。。<p></p> <p>然后放出两个查到的资料:</p> <p>JS小括号的作用</p> <p>JS声明变量的原理</p> <p> </p> <p>然后捏,上一张”闭包“的果照~(哇哈哈哈哈哈~)</p> <p> </p> <p> </p> <p>哇哈哈哈哈~  很上镜哦~</p> <p> </p> <p> </p> <p>最后,惯有的唠叨几句:</p> <p>话说再过两天就要回家了呀~  小心情还是很鸡冻滴~  还是觉的这个寒假要好好珍惜,嗯嗯~  多的就先不啰嗦了,等回家有时间再说吧~  嗯嗯,今天就到这里吧~  </p> <p>对了~  我觉得我得求一份工作了~  六月份就毕业了,o(︶︿︶)o 唉~  桑不起呀~  </p> <p>好了好了,就到了这了,还是祝大家都开心哈~</p> [1]: https://secbone.com/usr/uploads/2015/08/1171503046.jpg

<p>话说今天调了一个bug,先叙述一下过程吧:</p>
<p></p>

if(!Array.prototype.indexOf){
    Array.prototype.indexOf = function(obj){
        for(var i=0; i&lt;this.length; i++){
            if(this[i]==obj){
                return i;
            }
        }
        return -1;
    }
}

<p> 这段代码估计很多人用过吧,他是用来解决IE下没有indexOf这个问题的,也就是因为这段代码,才出现的IE下for in的问题(好吧,都是万恶的IE。。。。。)</p>
<p>当还没加上这段代码的时候</p>

var a = [1,2,3];
for( var k in a){
    alert(a[k]);
}

这样没有任何问题,结果是1,2,3。。。。<p></p>
<p>但是,当加上上面的代码时,奇迹就发生了,他会先打出上面的function,然后再1,2,3。。。。。。</p>
<p>额。。。  神一样的蛋疼。。。</p>
<p>大概的意思就是IE下用for in的时候,不光会遍历出数组的值,还会遍历出你新添加的方法。。。。  </p>
<p>所以,大家以后在IE下用for in请小心喽~</p>
<p>解决办法嘛,目前我想到的就是加一个判断:</p>

for( var k in a){
    if( k == "indexOf")
        continue;
    .........
}

<p>或者是:</p>

for( var k in a){
    if(!isNaN(k)){
        .........
    }
}

大概就是这个样子,如果高手有好的方法的话,希望留言告诉我一下,先在这儿谢谢啦~<p></p>
<p>嗯嗯,差不多就这个样子,然后就是,话说这个周五要世界末日了,亲们还有什么想做的赶紧去行动吧~</p>

这是在别的地方翻到的代码,但是它原来的有一点小问题,自己把它改进了一下,发出来标记一下,方便自己以后找。。

function numberFormat(num, decimal, dec, spe) { 
     decimal = (undefined === decimal) ? 0 : decimal; 
     decimal = parseInt(decimal); 
     dec  = (undefined === dec) ? '.' : dec; 
     spe  = (undefined === spe) ? ',' : spe; 
     num  = parseFloat(num) + ''; 
 
     var length, tmp, left, right; 
     length = num.length; 
     tmp  = num.split('.', 2); 
     left = tmp[0]; 
     left = _split(left, 3, spe); 
 
     right = (undefined === tmp[1]) ? '' : tmp[1]; 
     right = _pad(right, decimal); 
 
     if (0 == right.length) { 
         num = left; 
     } else { 
         num = left + dec + right; 
     } 
 
     return num; 
 
     function _split(str, len, spe) { 
         var l  = str.length; 
         var tmp = new Array(); 
    
         if (l > len) { 
             var b = l % len; 
 			if(b == 0)
 				b = len;
             var ts = str.substr(0, b); 
             tmp.push(ts); 
    
             while (b < l) { 
                 var ts = str.substr(b, len); 
                 tmp.push(ts); 
                 b += len; 
            } 
           str = tmp.join(spe); 
       } 
    
         return str; 
     } 
    
     function _pad(str, len) { 
         var l = str.length; 
    
         if (l < len) { 
             for (var i = 0; i < (len - l); i++) { 
                  str += '0'; 
            } 
        } else { 
               str = str.substr(0, len); 
        } 
    
         return str; 
     } 
 }

嗯嗯  numberFormat(num, decimal, dec, spe)  

第一个参数是要格式化的数字,

第二个参数是小数点后的位数(可选,默认0),

第三个参数是小数点的样式(可选,默认'.'),

第四个参数是分隔符的样式(可选,默认',')

 

嗯嗯  来个例子:numberFormat(1234,2);  输出为  1,234.00

嗯嗯 大概就是这个样子~

    这篇日志主要是给自己mark一下,留着以后有用的时候方便找的,下面贴代码:

    var x = document.documentElement.scrollLeft + e.clientX;

    var y = document.documentElement.scrollTop + e.clientY;

 

    以上方法可以兼容IE6的鼠标位置,然后用jquery获取元素位置即可得出鼠标的相对位置来,下面再贴张图,虽然我还没看懂,不过估计有用,先留着~

 

    点击查看原图

 

    嗯嗯,就这么多~