《JavaScript高级编程》事件及最佳实践简记

  • 5种类型:undefined, boolean, string, number, object
    • 使用typeof结果新增:null, function
  • ECMAScript5中为数组提供五种迭代方法
    • every(), filter(), forEach(), map(), some()
    • every和some:数组中数据是否满足条件,return true/false
  • 使用函数的值取代函数名
    • 如下错误
    		function(){
    			//这里是块级作用域
    		}();  //出错
    
  • 可修改为如下:
    		(function(){
    			//这里是块级作用域
    		})();  //正确
    
  • DOM1没有规定事件处理
    • DOM0级,绑定click方法,只能单个事件
    • DOM2级,addEventListener(),可以多个事件
      • 包含三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
    • DOM3级,包括以下及部分内容
      • UI事件
        • load, unload, select, resize
      • 焦点事件
        • focus
      • 鼠标事件
        • mousedown
        • mouseup
        • click
        • mousedown
        • mouseup
        • click
        • dbclick
      • 滚轮事件
        • mousewheel
      • 键盘事件
        • keydown
        • keypress
        • keyup
      • 文本事件
        • textInput
      • 复合事件
        • 仅有IE9+支持
      • 变动事件
        • DOM中的某一部分发生变化时给出提示
  • JavaScript最佳实践
    • 可维护性
      • 可维护的代码
        • 可理解性
        • 直观性
        • 可适应性
        • 可扩展性
        • 可调试性
      • 代码约定
        • 可读性
        • 变量和函数命名
        • 变量类型透明
          • 使用合适的命名方式
          • 匈牙利标记法
            • o:对象
            • s:字符串
            • i:整数
            • f:浮点数
            • b:布尔型
          • 类型注释
      • 松散耦合
        • 解耦HTML/JavaScript
        • 解耦CSS/JavaScript
        • 解耦应用逻辑/事件处理程序
      • 编程实践
        • 尊正对象所有权
          • 简单的说:如果不负责创建或维护某个对象,就不能对它们进行修改
          • 具体地说:
            • 不要为实例或原型添加属性
            • 不要为实例或原型添加方法
            • 不要重定义已存在的方法
        • 避免全局量
        	//两个全局量——避免!!
        	var name = "Nicholas"'
        	function sayName(){
        		Alert(name);
        	}
        	
        	//一个全局量——推荐
        	var MyApplication = {
        		name : "Nicholas",
        		sayName : function(){
        			alert(this.name);
        		}
        	};
        
        • 避免与null进行比较
          • 如果值应为一个引用类型,使用instanceof操作符检查其构造函数
          • 如果值应为一个基本类型,使用typeof检查其类型
          • 如果是希望对象包含某个特定的方法名,则使用typeof操作符确保指定名字的方法存在于对象上。
          • 代码中的null比较越少,就越容易确定代码的目的,并消除不必要的错误
        • 使用常量
          • z定义Constants类,编写常量key/value值
          • 重复值
          • 用户界面字符串
          • URLs
          • 任意可能会更改的值
    • 性能
      • 注意作用域
        • 避免全局查找(涉及作用域链上的查找)
        • 避免with语句
      • 选择正确方法
        • 避免不必要的属性查找(一次查找复杂度O(n))
          • 一旦多次用到对象属性,应该将其存储在局部变量中
        • 优化循环
          • 减值迭代(很多情况下更高效)
          • 简化终止条件
          • 简化循环体
          • 使用后测试循环(避免第一次的判断)
        • 展开循环
          • 当循环次数是确定的,消除循环并使用多次函数调用往往更快
            • 可以消除建立循环和处理终止条件的额外开销
          • 若迭代次数不能事先确定,可以考虑使用一种叫Duff装置的技术
      		 // Jeff Greenberg for JS implementation of Duff's Device
      	  // 假设:values.length 0
      	  function process(v) {
      	      alert(v);
      	  }
      	  var values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
      	  var iterations = Math.ceil(values.length / 8);
      	  var startAt = values.length % 8;
      	  var i = 0; 
      	  do {
      	      switch(startAt) {
      	          case 0 : process(values[i++]);
      	          case 7 : process(values[i++]);
      	          case 6 : process(values[i++]);
      	          case 5 : process(values[i++]);
      	          case 4 : process(values[i++]);
      	          case 3 : process(values[i++]);
      	          case 2 : process(values[i++]);
      	          case 1 : process(values[i++]);
      	      }
      	      startAt = 0;
      	  }while(--iterations 0);
      
      • 达夫设备背后的基本理念是:
        • 每次循环中最多可8次调用process()函数,循环迭代次数为元素总数除以8
        • 因为总数不一定是8的整数倍,所以startAt变量存放余数,指出第一次循环中应当执行多少次process()。
        • 比方说现在有12个元素,那么第一次循环将调用process()4次,第二次循环调用process()8次,用2次循环代替了12次循环。
        • tips: case语句找到第一个匹配的语句之后,未遇见break语句时,后面的语句将会依次执行。
      • 03年改进版本,先处理余数部分,几乎增速40%
        	// Speed Up Your Site(New Riders, 2003)
        	  function process(v) {
        	      alert(v);
        	  }    
        	  var values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
        	  var iterations = Math.floor(values.length / 8);
        	  var leftover = values.length % 8;
        	  var i = 0; 
        	  if(leftover 0) {
        	      do {
        	          process(values[i++]);
        	      }while(--leftover 0);
        	  }    
        	  do {
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	      process(values[i++]);
        	  }while(--iterations 0);
        
    • 避免双重解释
      • 在以下例子中,都要解析包含JavaScript代码的字符串
      • 这是不能再初始的解析过程中完成的,因为代码是包含字符串中的。
      • 必须在代码运行的同时新启动一个解析器来解析
      • 实例化一个新的解析器有不容忽视的开销
      	//某些代码求值——避免!!
      	eval("alert('Hello world!')");
      	//某些代码求值——已修正
      	alert('Hello world!');
      	
      	//创建新函数——避免!!
      	var sayHi = new Function("alert('Hello world!')");
      	//创建新函数——已修正
      	var sayHi = function(){
      		alert('Hello world!');
      	};
      	//设置超时——避免!!
      	setTimeout("alert('Hello world!')", 500);
      	//设置超时——已修正
      	setTimeout(function(){
      		alert('Hello world!');
      	}, 500);
      
    • 性能的其他注意事项
      • 原生方法较快
      • Switch语句较快
      • 位运算符较快
  • 最小化语句数
    • JavaScript代码中语句数量也影响所执行的操作的速度
    • 完成多个操作的单个语句要比完成单个操作的多个语句快
    1. 多个变量声明
    	//4个语句——很浪费
    	var count = 5;
    	var color = "blue";
    	var values = [1, 2, 3];
    	var now = new Date();
    	
    	//一个语句
    	var count = 5,
    		color = "blue";
    		values = [1, 2, 3];
    		now = new Date();
    
    1. 插入迭代值
    	var name = values[i++];
    
    1. 使用数组和对象字面量
    	//用4个语句创建和初始化数组——浪费
    	var values =  new Array();
    	values[0] = 123;
    	values[1] = 456;
    	values[2] = 789;
    	//用1个语句创建和初始化数组
    	var values =  [123, 456, 789];
    	
    	//用4个语句创建和初始化对象——浪费
    	var person = new Object();
    	person.name = "nicholas";
    	person.age = 29;
    	person.sayName = function(){
    		alert(this.name);
    	}
    	//用1个语句创建和初始化对象
    	var person = {
    		name = "nicholas",
    		age = 29,
    		sayName = function(){
    			alert(this.name);
    		}
    	}
    
  • 优化DOM交互
    1. 最小化现场更新(部分更新)
    2. 使用innerHTML
      使用时构建好一个字符串然后一次性调用innerHTML要比调用innerHTML多次快得多
    3. 使用事件代理
      可以将事件处理程序附加到更高层的地方(祖先节点)负责多个目标的事件处理。
    4. 减少调用HTMLCollection次数

猜你喜欢

转载自blog.csdn.net/weixin_43236610/article/details/82782437