【读书笔记】读《JavaScript高级程序设计-第2版》 - 非函数部分
章节列表:
第08章:BOM
第09章:客户端检测
第10章:DOM
第11章:DOM2和DOM3
第12章:事件
第13章:表单脚本
第14章:错误处理与调试
第17章:Ajax和JSON
第20章:最佳实践
片段串接:
1 (function($){ 2 3 /** 4 * 第8章:BOM 5 * window对象的核心函数 6 * 1>超时调用和间歇调用 7 * 2>核心对象: 8 * a>location 9 * b>navigator 10 * c>screen 11 * d>history 12 */ 13 //超时调用和间歇调用 14 (function(){ 15 window.setTimeout('alert("hello world!")', 1000); //不推荐传递字符串 16 var timeoutId = window.setTimeout(function(){ //推荐方式 17 alert('hello world!'); 18 }, 5000); 19 //只要在指定的事件尚未过去之前调用clearTimeout(),就可以完全取消超时调用 20 //有时,没有必要跟踪超时调用ID,因为每次执行代码之后,如果不再设置另一次超时调用,调用就会自行停止 21 clearTimeout(timeoutId); 22 //间歇调用,间歇调用的ID我们一般是需要跟踪的 23 var intervalId = setInterval(function(){ 24 alert('hello world!'); 25 }, 1000); 26 clearInterval(intervalId); 27 })(); 28 29 /** 30 * 第9章:客户端检测 31 * 能力检测:在编写代码之前先检测特定浏览器的能力。 32 * 怪癖检测:检测浏览器实现中的bug。 33 * 用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器相关的信息,包括浏览器、平台、操作系统及浏览器版本。 34 */ 35 36 /** 37 * 第10章:DOM 38 * 节点层次:类型(Document类型、Element类型、Text类型、Attr类型等等)、关系、操作。 39 * DOM1级主要定义的是HTML和XML文档的底层结构 40 * 1>节点层次 41 * a>Node类型:文档节点、元素节点、属性节点、文本节点、注释节点等等。 42 * i>节点名字nodeName和节点值nodeValue 43 * ii>节点关系 44 * iii>操作节点 45 * b>文档节点Document 46 * i>文档子节点<html>: var html = document.documentElement; 47 * ii>文档信息:title、URL、domain、referrer 48 * iii>查找元素 49 * iv>特殊集合 50 * v>DOM一致性检测 51 * c>元素节点Element 52 * d>文本节点Text 53 */ 54 //DOM1 55 (function(){ 56 var ele = document.getElementById('container'); 57 58 //注意:Node.ELEMENT_NODE在IE中是无效的 59 console.log(ele.nodeType === Node.ELEMENT_NODE); 60 61 //适用于所有浏览器 62 if (ele.nodeType === 1) { 63 console.log('element node'); 64 console.log(ele.nodeName); 65 console.log(ele.nodeValue); 66 } 67 68 //节点的关系 69 //document对象是window对象的一个属性,可以把其当做全局对象来访问 70 console.log(window.document); //HTMLDocument(#document)——对象 71 console.log(window.document.documentElement); //HTMLHtmlElement 72 73 var html = document.documentElement; 74 console.log(html === document.firstChild); //true 75 console.log(html === document.childNodes[0]); //true 76 77 document.title = 'xxxxxx'; 78 })(); 79 80 /** 81 * 第11章:DOM2和DOM3 82 * 元素大小: 83 * 1>偏移量:offset系列(offsetLeft,offsetTop,offsetWidth,offsetHeight) 84 * 2>客户区:client系列(clientWidth,clientHeight) 85 * 3>滚动条:scroll系列(scrollLeft,srollTop,scrollWidth,scrollHeight) 86 * DOM遍历 87 * DOM范围 88 */ 89 90 /** 91 * 第12章:事件 92 * ------------------------------第一部分----------------------------------- 93 * 1>每个元素都有自己的事件处理程序属性,将这种属性的值设置为一个函数,就可以指定事件处理程序。 94 * 2>使用DOM0级方法指定的事件处理程序被认为是元素的方法。 95 * 因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的this引用当前元素。 96 * var btn = document.getElementById('myBtn'); 97 * btn.onclick = function () {...} 98 * 以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。 99 * 删除DOM0级事件处理程序的方法是将对应事件处理程序属性的值赋值为null 100 * 3>DOM2级事件 101 * btn.addEventListener('click', function(){...}, false); 102 * btn.removeEventListener('click', handler, false); 103 * false表示冒泡阶段,true表示捕获阶段 104 * 4>IE事件处理程序attachEvent()和detachEvent()。 105 * 106 * ------------------------------第二部分------------------------------------ 107 * 1>事件处理程序数量直接会影响到页面的整体性能: 108 * a>事件处理函数占用内存 109 * b>必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。 110 * 2>由此,启用事件委托: 111 * a>什么情况下用? 112 * b>优势在哪儿? 113 * 3>为document对象添加事件处理程序 114 * a>分析与传统的事件处理程序设置相比的优势 115 * 4>每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的JavaScript代码之间就会建立一个连接。 116 * 因此,限制建立的连接数量是提高性能的方式,可采用事件委托。 117 * 另外,在不需要的时候移除事件处理程序,也是提高性能的方法。 118 * 5>模拟事件 119 * var myEvent = document.createEvent("MouseEvents"); 120 * myEvent.initEvent("click", false, false); 121 * elm.dispatchEvent(myEvent); 122 * 6>事件冒泡: 123 * 无法冒泡的事件:blur、focus、load、unload 124 * 125 */ 126 //jquery事件绑定 127 (function(){ 128 129 //最开始的方法 130 //最新的jQuery中bind目前其实最后也是调用on()方法来实现的, 131 //所以呢,如果现在大家使用最新jQuery版本(目前为1.7.1)的话,尽量避免使用bind()方法。 132 $('.scv').bind('click', function(){ 133 $('#container').append('<img class="scv" src="sth-bg.jpg" alt="鹿鼎记" />'); 134 }); 135 136 //克隆方法 137 $('.scv').bind('click', function(){ 138 $(this).clone(true).insertAfter(this); 139 }); 140 141 //live方法 142 //在最新的jQuery版本中,我们最好不要使用live()方法,因为它已经被放弃了 143 $('.scv').live('click', function(){ 144 $(this).clone(false).appendTo('#container'); 145 }) 146 147 //我们使用#container作为绑定的上下文,jQuery将会在#container这个元素中查询.scv元素 148 $('.scv', '#container').live('click', function(){ 149 $(this).clone(false).appendTo('#container'); 150 }) 151 152 //在最新的jQuery版本中,我们最好不要使用live()方法,因为它已经被放弃了, 153 //这里我们使用delegate方法来指定事件绑定的上下文 154 $('#container').delegate('.scv', 'click', function(){ 155 $(this).clone(false).appendTo('#container'); 156 }) 157 158 //其实在最新版本的jQuery类库中,所有以上方法在后面其实都是调用on()方法 159 $('.scv').on('click', function(){ 160 $(this).clone(true).appendTo('#container'); 161 }); 162 163 })(); 164 165 //事件冒泡和默认事件 166 (function(){ 167 168 $("body").click(function(){ 169 alert("body") 170 }) 171 172 $('a').click(function(){ 173 alert("xxxxx"); 174 175 //阻止事件传播 176 event.stopPropagation(); //ie不好使 177 window.event.cancelBubble = true; //全都好使 178 179 //阻止默认事件 180 window.event.returnValue = false; //全都好使 181 window.event.preventDefault(); //ie不好使 182 183 return false; //在jquery环境下,此句代码既能够阻止浏览器默认事件,也能够阻止事件冒泡 184 }) 185 186 187 var a = document.getElementsByTagName('a')[0]; 188 189 a.onclick = function(){ 190 alert('a element'); 191 192 event.stopPropagation(); //ie不好使 193 window.event.cancelBubble = true; //全都好使 194 195 //阻止默认事件 196 window.event.preventDefault(); //IE下不好使 197 window.event.returnValue = false; //全都好使 198 199 return false; //原生js下,这句代码无法阻止事件冒泡 200 //但能够阻止浏览器的默认事件 201 } 202 203 })(); 204 205 /** 206 * 第13章:表单脚本 207 */ 208 (function(){ 209 //取得表单 210 var myForm = document.forms[0]; //第一个表单 211 212 console.log(myForm.elements.length); //表单项:2 213 214 myForm.elements[0].select(); //聚焦并选中文本 215 216 })(); 217 218 /** 219 * 第14章:错误处理与调试 220 * IE:工具——>Internet选项——>高级——>浏览下.显示每个脚本的错误通知 221 */ 222 (function(){ 223 try { 224 window.king(); 225 } catch (error) { 226 alert(error.message); 227 } finally { 228 alert('haha'); //只要代码中包含finally子句,那么无论try还是catch语句块中的return语句都将被忽略。 229 //因此,在使用finally子句之前,一定要非常清楚你想让代码怎么样 230 } 231 })(); 232 233 /** 234 * 第17章:Ajax和JSON 235 */ 236 (function(){ 237 var obj1 = eval('{}'); //会把{}当做js处理,并未将其赋值,所以抛出错误 238 var obj2 = eval('({})'); //()在js中是一个表达式,没有问题 239 var jsonText = '{}'; 240 var obj3 = eval('(' + jsonText + ')'); 241 242 var jsonText1 = '{"name":"king","age":28,"author":true}'; //在json字符串中,其属性必须用引号括起来 243 var people = JSON.parse(jsonText1, function(key, value){ 244 switch (key) { 245 case 'age': return value + 1; 246 case 'author': return undefined; 247 default: return value; 248 } 249 }); 250 console.log(people.age); 251 console.log(people.author); 252 253 var json = '[1, 2, (function(){\ 254 alert("xxxxx");\ 255 })(), 4, 5]'; 256 257 var array = eval(json); //具有不安全性 258 var array = JSON.parse(json); //能够过滤恶意脚本 259 array[2]; 260 261 })(); 262 263 /** 264 * 第20章:最佳实践 265 * 266 * 1>可维护性 267 * (1)定义 268 * a>可理解性 269 * b>直观性 270 * c>可适应性 271 * d>可扩展性 272 * e>可调试性 273 * (2)代码约定: 274 * a>缩进、注释 275 * 注释在什么地方:函数和方法、大段代码、复杂的算法、Hack 276 * b>变量和函数命名 277 * 小写驼峰、合乎逻辑(如布尔型:is开头) 278 * c>变量类型透明 279 * 初始化指定:var found = false; 280 * 匈牙利标记法:var bFound;("b"代表布尔型...) 281 * 指定类型注释:var found /*:Boolean*/ = false; 282 * 2>松散耦合 283 * (1)解耦HTML/JavaScript 284 * i>从HTML角度 285 * a>避免内联代码的<script>元素 286 * b>避免使用HTML属性来分配事件处理程序 287 * ii>从JavaScript角度——避免在JavaScript中创建大量HTML 288 * a>页面中直接包含并隐藏对应HTML,在页面渲染之后,再用JavaScript显示该标记 289 * b>进行Ajax请求获取更多要显示更多HTML 290 * (2)解耦CSS/JavaScript 291 * i>从JavaScript角度 292 * 避免直接更改样式,而采用动态更改样式类 293 * ii>从CSS角度 294 * 避免使用css表达式 295 * (3)解耦应用逻辑/事件处理程序 296 * 从事件处理程序中分离应用逻辑,有以下3点原则 297 * i>勿将event对象传给其他方法;只传来自event对象中所需的数据; 298 * ii>任何可以在应用层面的动作都应该可以再不执行任何事件处理程序的情况下进行; 299 * iii>任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑。 300 * 3>编程实践 301 * (1)尊重对象所有权 302 * 永远不修改不是由自己所拥有的对象 303 * (2)避免全局量 304 * 推荐最多一个全局变量,让其他对象和函数存在其中 305 * 引入命名空间:将功能组合在一起的单一的全局量的延伸。 306 * (3)避免与null进行比较 307 * i>如果值应为一个引用类型,使用instanceof操作符检查其构造函数 308 * ii>如果值为一个基本类型 309 * iii>如果是希望对象包含某个特定的方法名,则使用typeof操作符确保指定名字的方法存在于对象上。 310 * (4)使用常量 311 * i>重复值——任何在多处用到的值都应抽取为一个常量。 312 * ii>用户界面字符串——任何用于显示给用户的字符串,都应被抽取出来以方便国际化。 313 * iii>URLs——在Web应用中,资源位置很容易变更,所以推荐用一个公共地方存放所有的URL。 314 * iv>任何可能会更改的值——每当在用到字面量值的时候,都要问一下自己这个值在未来是不是会变化。 315 * 如果答案是"是",那么这个值就应该被提取出来作为一个常量。 316 * 4>性能 317 * (1)注意作用域——将在一个函数中会用到多次的全局对象存储为局部变量。 318 * (2)选择正确的方法 319 * i>避免不必要的属性查找 320 * O(1):不管有多少值,执行的时间都是恒定的。一般表示简单值和存储在变量中的值。 321 * O(n):总执行时间和值的数量直接相关。 322 * 使用字面量、变量和数组要比访问对象上的属性更有效率,因为后者是O(n)操作。 323 * 一般来讲,只要能减少算法的复杂度,就要尽可能减少。尽可能多地使用局部变量将属性查找替换为值查找。 324 * ii>避免双重解释 325 * //某些代码求值——避免 326 * eval("alert('hello world')"); //用:alert('hello world'); 327 * //创建新函数——避免 328 * var sayHi = new Function("alert('hello world')"); 329 * //用:var sayHI = function(){alert('hello world');} 330 * //设置超时——避免 331 * setTimeout("alert('hello world')", 500); 332 * 用:serTimeout(function(){alert('hello world');}, 500)} 333 * 这些例子中都要解析包含了JavaScript代码的字符串。这个操作时不能在初始的解析过程中完成的, 334 * 因为代码是包含在字符串中的,也就是说在JavaScript代码运行的同时必须新启动一个解析器来解析新的代码。 335 * 实例化一个新的解析器有不容忽视的开销,所以这种代码要比直接解析慢得多。 336 * iii>其他方面 337 * a>原生方法较快 338 * b>switch语句较快 339 * c>位运算较快 340 * (3)最小化语句 341 * i>多个变量声明转变为单变量声明 342 * ii>插入迭代值 343 * 如:var name = values[i]; 344 * i++; 345 * 转换为: 346 * var name = values[i++]; 347 * ii>使用数组和对象字面量 348 * 如:var values = new Array(); 349 * values[0] = 123; 350 * values[1] = 456; 351 * values[2] = 789; //用4个语句创建和初始化数组——浪费 352 * 转换为: 353 * var values = [123, 456, 789]; //只用一条语句创建和初始化数组 354 * (4)优化DOM交互 355 * i>最小化现场更新 356 * 不管是怎样的一个DOM操作,对其都有一个性能惩罚,因为浏览器要重新计算无数尺寸以进行更新。 357 * 因此,完成一个操作所需的现场更新越少,代码就越快。 358 * 一旦需要更新DOM,请考虑使用文档碎片来构建DOM结构,然后再将其添加到现存的文档中。 359 * ii>使用innerHTML 360 * 而不用createElement()或appendChild()之类的DOM方法。 361 * iii>使用事件代理 362 * 事件处理程序的数量和页面响应用户交互的速度之间有个负相关。为了减轻这种惩罚,最好使用事件代理。 363 * iv>注意NodeList 364 * 任何时候要访问NodeList,不管它是一个属性还是一个方法,都是在文档上进行一个查询,这个查询开销很昂贵。 365 * var images = document.getElementsByTagName('img'); //生成的是一个NodeList 366 * for (var i = 0, len = images.length; i < len; i++) { //只调用了一次NodeList的length属性 367 * var image = images[i]; //避免在循环体内多次调用NodeList 368 * } 369 * 以下情况会返回NodeList对象: 370 * a>进行了对getElementsByTagName()的调用 371 * b>获取了元素的childNodes属性 372 * c>获取了元素的attributes属性 373 * d>访问了特殊的集合,如documents.forms、document.images等 374 * (5)部署 375 * i>构建过程——合并JavaScript文件(Ant等) 376 * 保存原有代码的逻辑结构,最好避免使用一个文件存放所有的JavaScript,遵循面向对象语言中的典型模式: 377 * 将每个对象或自定义类型分别放入其单独的文件中。这样可以确保每个文件包含最少量的代码,使其在不引入错误的情况下更容易修改。 378 * 要行进部署的时候,将这些源代码合并为一个或几个归并文件。 379 * ii>验证——JSLint 380 * iii>压缩 381 * a>文件压缩——如YUI压缩器 382 * 代码长度——压缩内容包括:删除额外的空白(包括换行)、删除所有注释、缩短变量名。 383 * b>HTTP压缩 384 * 配重指的是实际从服务器传送到浏览器的字节数—— 385 * 在服务器端压缩JavaScript文件,传输的字节数量大大减少,再由浏览器端解压缩。 386 * 387 */ 388 389 })(jQuery)