`

JavaScript高效图形编程学习笔记

 
阅读更多
第一章代码重用和优化
一、有关继承的一些笔记
1.在JS中,类的继承是可以通过prototype(原型方式),call等方式实现的,但是这种方式需要使用new来创建类,如果我们忘记使用类,那么this,返回值等问题就会出现,所以,需要考虑使用模块模式的方法,
var serialMaker=function(){
   //返回一个用来产生唯一字符串的对象。
   //唯一字符串由两部分组成:前缀+序列号
   //该对象包含一个设置前缀的方法,一个设置序列号的方法
   //和一个产生唯一字符串的gensym方法
   var prefix='';
   var seq=0;
   return {
    setPrefix:function(p){
            prefix=String(p);
    },
    setSeq:function(s){
            seq=s;
    },
    gensym:function(){
            var result=prefix+seq;
            seq+=1;//JS解释器并不是把seq+=1视作未声明的赋值语句,因为seq已经声明过了,内部函数可以访问外部函数的变量。
            return result;
    }
   };
};

当然也可以使用JS语言精粹第五章提到的
var mammal=function(spec){

       var that={};//第1步

       that.get_name=function(){//3

              return spec.name;

       };

       that.says=function(){

              return spec.saying||’’;

       };

       return that;//4

};
这个函数化的方法,相比与模块话的方法,函数化的方法,可以更好的提供封装

比如下面
var pet = function (name,legs){
   var that = {

      name:name,
      getDetails:function(){
         return that.name+'has'+legs+'legs';
      }
   };
return that;
};
var cat = function(name){
   var that = pet(name,4);
   that.action = function(){
     return 'Catch a bird';
   };
  return that;
};

var petCat2 = cat('Felix');
details = petCat2.getDetails();
action = petCat2.action();
petCat2.name = 'test';
petCat2.legs = 7;
details = petCat2.getDetails();
/*这里无法访问legs属性,因为legs属性存在于内部函数getDetails中,只有通过内部函数getDetails去进行访问,因为JS有函数级作用域。所以说这种方式封装的很漂亮。
*/
但是要注意使用这种方式不及原形继承的一点就是原形继承不管它被继承了多少次,对象的属性和方法只被保存一次。函数继承则相反,每个实例都会创建重复的属性和方法,如果你要创建许多(如上千个)大对象的实例,内存消耗可能会成为一个问题,不过这个问题很容易解决,可以将较大的属性或方法保存在一个对象中,并将其作为参数传给构造函数,这样所有实例就可以共同使用一个对象资源,而不是创建自己的版本


1.2优化什么,何时优化
1.这里要注意一件事情,之前我们学习了很多优化方式,但是要注意,一般来说,20%的代码将占用80%的cpu周期,所以,我们应该集中优化这20%,而忽略其他部分,这样可以保持很好的可读性。bug也会更少。


1.3自定义代码性能测试
1.一般使用基本的运行时间作为性能的测试评判标准,如
var startTime = new Date()..getTime();
//run some test code here
var timeElapsed  = new Date().getTime()-startTime;

但是这种方式可能因为垃圾回收,系统上运行的其他进程所影响,所以,我们可以考虑使用在相同时间内,看谁的循环次数多来评判。

var startTime = new Date()..getTime();
for(var iters = 0 ; timeElapsed<1000 ;iters++){
//run some test code here
timeElapsed = new Date().getTime()-startTime;
}
//iters = number of iterations achieved in 1000 millseconds
使用这种方式。通过循环次数的多少来判断性能。

1.4优化Javascript
1.4.1查找表
对于一些高开销用的计算,我们可以事先将结果运算好,然后放在一个数组,也就是查找表中。
比如,对于Math.sin()方法,可以使用这样的方式来减少运算开销。
var fastSin = function(steps){
   var table = [],
         ang = 0,
         angStep =(Math.PI * 2) / steps;
   do{
       table.push(Math.sin(ang));
       ang+=angStep;

   }while(ang<Math.PI * 2);
return table;
};

1.4.2位操作、整数、二进制数
1.JavaScript位操作,
与操作& 也可以达到类似取余运算符%的效果,也就是返回除法后的余数,下面的代码将保证变量value总是在0到7之间,
value&=7;//Equivalent to value % 8;
不过这种等价只有在&后面的值是2的幂-1时才成立。也就是在对2的幂取余的运算成立。

位异或,如果两个操作数的某一位只有一个为1,将对应结果位设1。这很方便地用于切换变量。
toggle^=1
当然这里的toggle 原来的值是1或0,那么每次执行toggle^=1 toggle的值将在1和0之间转换。

位非:对所有位进行取反,例如1110011将变成00011000,如果操作数是有符号整数,则~操作符等于取负减1,前面提到过,补码中取负对应各位取反加1。

位左移,对x的二进制向左移numBits位,所有位向左移,最左的位丢失,0填补最右的位。这等价于无符号整数的乘法 x*2^numBits
y = 5<<1 // 等价于Math.floor(5*2^1)
y = 5 <<2//等价于Math.floor(5*2^2)也就是5*4

算术位右移:对x的二进制向右移numBits位,除了(最左)符号位,所有位向右移,最右位丢失,这相当于有符号整数除法 x/2^numBits
例如 y =10>>1;//y=5等价于Math.floor(5/(2^1))
y =10>>2//y=2等价于Math.floor(5/(2^2))
y =10>>3//y=1等价于Math.floor(5/(2^3))

注意上面的这个位左移和算术位右移,和对应的乘法运算和除法运算。相比就没有性能提升。但是下面这个代码虽然看似毫无用处。但是在性能方面有着提升
x=y>>0;
这个使的JS调用其内部的整数转换函数,剔除数字的小数部分,这实际上是一个快速的Math.floor()函数。在ie8,chrome,safari中都有性能的提升。

逻辑位右移x>>>y:类似>>,但符号位不保留而填补为0,对正数来说,这个>没有区别,对负数来说,逻辑位右移的结果将变为正数。

3.循环展开,麻烦的真相
达夫设备指的是由Tom Duff在1983年开发的一种循环展开的C语言优化技术,循环展开是汇编语言中常用的技术,细小的优化就可以在内存复制等领域发挥作用。具有优化功能的编译器也可能进行自动的循环展开。

但是这种方法比较适合于循环迭代次数很多,并且循环体开销(循环的操作)比循环开销要大的多。这个时候使用这个效果才好,一般来说,我们需要在实际的背景下测试这种优化技术是否值得我们使用。

1.5优化jQuery与DOM交互
1.5.1优化CSS格式变化
比如 $('#element1');.css('color','#f00');
这个语句首先,调用jQuery并让它在DOM中搜索一个id 为element1的元素,除了搜索本身之外,他还涉及进行正则表达式测试来决定需要搜索的类型。
第二步,返回找到的元素列表,一个特殊的jQuery数组对象。
第三步,调用jQuery的css函数,这会进行不同的检查,如决定读写,是否传入一个字符串参数,对象或者更多。最后更新元素样式本身。
重复运用上面$('#element1');.css('color','#f00');
$('#element1');.css('color','#0f0');
$('#element1');.css('color','#00f');
会十分没有效率
针对上面这三个步骤,有如下的优化方法,
针对第一个步骤,尝试指定jQuery的搜索范围,jQuery默认从document根或是DOM层次的最上层开始搜索,这完全没有必要,我们可以指定一个搜索范围,比如说
$alien = $('.alien',container);这个container是灵活的,可以是另一个jQuery对象或是css选择器。
$alien = $('.alien',$container);
$alien = $('.alien','#container');
当然要确保搜索环境不比搜索元素本身慢,

针对第二步,我们可以使用一个局部变量存储中间结果
var $elem = $('#element1');.css('color','#f00');//这个$只是代表他是一个jQuery对象。可以使用这种方式!表明这个变量是jQuery对象。
$elem.css('color','#0f0');
$elem.css('color','#00f');

针对第三步,使用
var elemStyle = $('#element1')[0].style
elemStyle.color= '';

另外直接操作元素属性本身比使用jQuery要快,比如jQuery.html() 方法要比直接使用一个元素的innerHTML慢许多。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics