js内部实现
在js以外的很多语言中,数组将会隐式占用一段连续的内存空间。
这种隐式的内部实现,使得高效的内存使用及高速的元素方法称为可能,而
在javascript中,数组实体是一个对象,所以通常的实现方式
并不是占用一段连续的内存空间
比较下面2段代码
<script> //代码1 var arr=[]; for(var i=0;i<1e7;i++){ arr[i]=''; } //代码2 var arr={}; for(var i=0;i<1e7;i++){ arr[i]=''; } </script>
根据实现方式的不同,代码1和代码2的执行速度会有所差异,这其实是数组是否使用连续的内存空间的一种体现。
然而如果数组内部总是使用连续的内存空间,下面代码就应该占用多达GB量级的连续内存,不过在一般的实现中,这样的情况不糊发生
<script> var arr=[]; arr[1e9]=''; </script>
在流行的jsvascript实现中,小型的数组(下标值较小的部分)会占用连续的内存空间,而下标值较大的部分,
则一般会以类似于对象的形式进行处理
此外在js中 也有人提出需要增加Int32Array或Int8Array这类自定义增强功能
数组风格的对象调用Array类的方法
<script> var fake_arr={0:'zero',1:'one',2:'two',length:3} fake_arr.join(',');//Uncaught TypeError: undefined is not a function p(Array.join(fake_arr,','));//zero,one,two firefox可以运行 其它浏览器可能报错 Array.push(fake_arr,'three'); p(fake_arr.length);//4 p(Array.join(fake_arr,'_'));//zero_one_two_three //另外一种 p(Array.prototype.join.call(fake_arr,'-')); // zero-one-two-three 更多浏览器支持了 </script>
迭代器
一种专门为循环操作设计的对象
在javascript中有Iterator类这样一个自定义增强功能。
可以通过构造函数调用或Iterator函数的调用来生成一个对象实例,这时需要将想要枚举的目标对象传递个它的第一个参数
在迭代器对象中含有一个next方法,可以从对象或元素的集合中返回下一个所需的元素
下面代码在firefox下正常运行,在其他浏览器中可能出问题
<script> var arr=['zero','one','two']; var it=new Iterator(arr,true); p(it.next());//0 单个元素 p(it.next());//1 p(it.next());//2 p(it.next());//uncaught exception: [object StopIteration] //如果第二个参数为false var it=new Iterator(arr,false); p(it.next());//[0 ,zero ] 数组 p(it.next());//1 one p(it.next());//2 two p(it.next());//uncaught exception: [object StopIteration] </script>
对Iterator使用for in
<script> var arr=['zero','one','two']; var it=new Iterator(arr,false); for(var item in it){ for(var k in item){ p(k+":"+item[k]); } p("--------------------------------------") } /*输出 0:0 1:zero -------------------------------------- 0:1 1:one -------------------------------------- 0:2 1:two -------------------------------------- */ </script>
对于已经存在的对象或数组来说,使用Iterator没有太大作用
for in等语句已经足够
使用场景:自定义迭代器
代码如下(测试时在firefox下好使)
<script> //迭代器的目标对象 function Factorial(max){ this.max=max; } //自定义迭代器 function FactorialIterator(factorial){ this.max=factorial.max; this.count=this.current1=1; } //迭代器的实现 FactorialIterator.prototype.next=function(){ if(this.count>this.max){ throw StopIteration; }else{ return this.current1*=this.count++; } } //将Factorial与FactorialIterator相关联 //__iterator__属性是一种特殊属性 Factorial.prototype.__iterator__=function(){ return new FactorialIterator(this); } var obj=new Factorial(5); for(var n in obj){ p(n) } /* 结果 1 2 6 24 120 */ </script>
生成器
和迭代器一样,生成器(Generator)也是javascript自定义的增强功能,其作用是帮助执行循环处理
从表面上看,生成器就像一个普通的函数.生成器与普通函数的不同之处在于是否在内存进行yield调用。
一个函数如果在内部进行yield调用,它就是一个隐式的生成器
输出阶层的函数
<script type="application/javascript;version=1.7"> function jc_prnt(max){ var cur=1; for(var n=1;n<=max;n++){ cur*=n; p('curl='+cur); } } jc_prnt(5); /*输出 curl=1 curl=2 curl=6 curl=24 curl=120 */ </script>
如果在js_print函数里的p(打印)函数之前调用yield
就变成了如下代码
<script type="application/javascript;version=1.7"> function jc_prnt(max){ var cur=1; for(var n=1;n<=max;n++){ cur*=n; yield(cur); p('curl='+cur); } } var g=jc_prnt(5); p(g.next());//1 p(g.next());//curl=1 2 p(g.next());//curl=2 6 p(g.next());//curl=6 24 p(g.next());//curl=24 120 p(g.next());//curl=120 报错 </script>
由于从内部看迭代生成器是一个迭代器,所以可以将next方法调用隐藏在for in循环的内部
js_print函数同上
<script type="application/javascript;version=1.7"> var g=jc_prnt(5); for(var n in g){ p(n,'------------'); } /* 1 ------------ curl=1 2 ------------ curl=2 6 ------------ curl=6 24 ------------ curl=24 120 ------------ curl=120 */ </script>
可将生成器理解为一种由于yield而处于停滞状态的函数。
在调用next时,生成器的循环将执行一次,更确切的说,这一执行过程与循环没有关系,只是执行生成器的代码直至下一次调用yield
处
数组的内包
数组的内包是一种在通过生成器生成数组时的功能
<script type="application/javascript;version=1.7"> function jc_prnt(max){ var cur=1; for(var n=1;n<=max;n++){ cur*=n; yield(n); } } var arr=[i for each (i in jc_prnt(5))]; p(arr);//数组 1,2,3,4,5 //也可过滤 var arr=[ i for each (i in jc_prnt(5)) if (i>3)]; p(arr);//4,5 数组 </script>
注意,上面所有的代码 由于是javascript里的自定义增强功能有的浏览器还不支持,在firefox下运行良好,可以在firefox下测试