javascript编程技巧与优化

91
Javascript 技技技技技 kim

Upload: ho-kim

Post on 15-Jan-2015

1.781 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Javascript编程技巧与优化

Javascript 技巧与优化

kim

Page 2: Javascript编程技巧与优化

问题 1

• Javascript 对于你来说是?

Page 3: Javascript编程技巧与优化

• Javascript 是 PHP 程序员最头痛的事

Page 4: Javascript编程技巧与优化

问题 2

• 为什么要把 Javascript 放在 </body> 之前?

Page 5: Javascript编程技巧与优化

• IE 经典错误“ operation aborted”

• 不阻塞页面解析

Page 6: Javascript编程技巧与优化

问题 3

• Javascript 为什么这么令人崩溃?

Page 7: Javascript编程技巧与优化

• 严苛的浏览器环境

• 变态的兼容问题,各种不同的内核、引擎

• 单线程,阻塞也得靠浏览器

Page 8: Javascript编程技巧与优化

技巧

Page 9: Javascript编程技巧与优化

• If 、 switch 、 for 语句都用 {} 括起来

Page 10: Javascript编程技巧与优化

• js 文件几个注意的地方:

1. 统一用 UTF-8 编码 2. 文件头和尾都写上 “ ;” 3. 所有注释使用 /**/ 4. 文件头写上 document.domain =

"56.com"; 方便跨域使用

Page 11: Javascript编程技巧与优化

• typeof (null) == 'object' 是 true

Page 12: Javascript编程技巧与优化

• var a;• a == undefined 是 true

Page 13: Javascript编程技巧与优化

• null == undefined 是 true• null === undefined 则是 false

Page 14: Javascript编程技巧与优化

• 字符串连接优先级高于算术运算:• 1 + '1' + 1 = '111’• '2' - 1 - 1 = 0

Page 15: Javascript编程技巧与优化

• switch 语句很快

• 把发生几率最高的 case 放在前面

Page 16: Javascript编程技巧与优化

• HTML5 是个无底洞

Page 17: Javascript编程技巧与优化

• js 没有函数重载概念: function foo(a) { alert(1); } function foo(a, b) { alert(2); } var f = foo(100); // alert 2

Page 18: Javascript编程技巧与优化

• var a = '1';• var b = {n:'kim'};• var c = a; // 值复制• var d = b; // 引用复制

Page 19: Javascript编程技巧与优化

• 初始化对象尽量使用字面量语法:

var obj = { "name": "kim", "age": 18 };

Page 20: Javascript编程技巧与优化

• RegExp 构造函数中的反斜杠需要双重转义:

// 比如匹配 2.5 、 3.4 等小数 var e = /\d.\d/; var e = new RegExp("\\d.\\d");

Page 21: Javascript编程技巧与优化

• 递归函数的定义: var factorial = (function f(num){ if (num <= 1) { return 1; } else { return num * f(num - 1); } });

Page 22: Javascript编程技巧与优化

• 理解 this 对象 : 当前的环境对象:

window.name = 'win'; var obj = {name: "kim"}; function myEnv() { alert(this.name); } myEnv.call(window); // win myEnv.call(obj) // kim

Page 23: Javascript编程技巧与优化

• 取 a-b 中间的随机数公式:

• var rand = Math.floor(Math.random() * b + a);

Page 24: Javascript编程技巧与优化

• prototype :定义对象的祖宗。

• 如果不了解 prototype ,那就别使用它,一般工厂模式或者单例模式就够用了

Page 25: Javascript编程技巧与优化

• 标准单例定义模式:

var singleton = function() { var private = 'hey'; function somePrivateFunc() { return 'hi'; } var public = { “name”: “kim”, getPrivate: function() { alert(private + somePrivateFunc()); } } return public; }(); var s = singleton; s.getPrivate();

Page 26: Javascript编程技巧与优化

• 跨浏览器取得窗口左上角位置:

• var left = (window.screenLeft ? window.screenLeft : window.screenX);• var top = (window.screenTop ? window.screenTop : window.screenY);

Page 27: Javascript编程技巧与优化

• url 跳转的几种方式:

window.location = 'http://example.com/'; location.href = 'http://example.com/'; location.assign('http://example.com/'); // 用 replace 的区别是取代 history 中的记

录 location.replace('http://example.com/');

Page 28: Javascript编程技巧与优化

• 用 location 页内跳转:

• // url 变成 http://example.com/#hash1 location.hash = '#hash1';• // url 变成 http://example.com/user/#hash1 location.pathname = 'user';• // url 变成 http://www.56.com/user/#hash1 location.hostname = 'www.56.com';

Page 29: Javascript编程技巧与优化

• 除非是紧急 bug ,或者小范围的修改,否则不要用浏览器检测,而应该用功能检测:

// 正确 if (document.all) { // do something with document.all } // 错误 if (browser.isIE) { // do something with document.all } else { // do nothing with document.all }

Page 30: Javascript编程技巧与优化

• 获取 html 元素:

document.documentElement document.firstChild document.childNodes[0]

Page 31: Javascript编程技巧与优化

• 2 个子域页面共享 js 对象:

• document.domain = “example.com”

Page 32: Javascript编程技巧与优化

• document.write 输出 script 需注意:

• document.write("<script type=\"test/javascript\" src=\"objcmt.js\">" + "<\/script>");

Page 33: Javascript编程技巧与优化

• 屏幕滚动到该元素: div.scrollIntoView();

Page 34: Javascript编程技巧与优化

• 站内 js 的兼容测试:必须按实际情况,根据各浏览器的访问数据为依据

Page 35: Javascript编程技巧与优化

• 访问 iframe 中的 document :

• var iframe = document.getElementById('ifrm');• var ifrmdoc = iframe.contentDocument || iframe.contentWindow.document;

Page 36: Javascript编程技巧与优化

• 谨记 DOM 事件流:

• 捕捉阶段:• document -> html -> body -> ... -> div

• 冒泡阶段:• div -> ... -> body -> html -> document

Page 37: Javascript编程技巧与优化

• setTimeout 高级定时器:

f = setTimeout(function () { objcmt.ajaxFlvHeartbeat(); f = setTimeout(arguments.callee, 180000); }, 180000);

Page 38: Javascript编程技巧与优化

• IE 经典错误:

• “ 缺少标识符、字符串或数字”,一般就是多了个逗号

Page 39: Javascript编程技巧与优化

• IE 经典错误:

• “ 无效字符”,转义前面缺了引号,或者字符串中的引号缺了转义

Page 40: Javascript编程技巧与优化

• 判断参数是否传入:

function foo(param1, param2) { if (param1) { // bad } if (typeof param1 != 'undefined') { // good, go on } if (param2 instanceof Function) { // better, go on do with function } }

Page 41: Javascript编程技巧与优化

• instanceof, typeof 等等都不是 100% 正确的,最实际的做法是直接判断该对象,或者该方法是否可用,比如 :

if (document.all) { // do something with document.all }

Page 42: Javascript编程技巧与优化

• 不要用各种 javascript 模板技术,从个人经验来看,这些模板技术只会添乱

Page 43: Javascript编程技巧与优化

• 不要“添加、修改、重定义”已有实例或对象的属性和方法

Page 44: Javascript编程技巧与优化

• 两者的区别?• var obj1 = {"name": "kim"}• var obj1 = {name: "kim"}

Page 45: Javascript编程技巧与优化

• JSONP 的原理:

function myCallback(rep) { alert(rep); } var script = document.createElement('script'); script.src = "http://comment.56.com/api/api.php?callback=myCallback"; document.body.appendChild(script);

// api.php <?php if (isset($_GET['callback'])) { echo htmlspecialchars($_GET['callback'] . '()'); } exit(); ?>

Page 46: Javascript编程技巧与优化

• 尽量少用框架,或者基于框架开发的组件

Page 47: Javascript编程技巧与优化

• 网站流量统计:嵌入 js 方式的统计,比服务器日志更准确,因为客户端有缓存。

Page 48: Javascript编程技巧与优化

• 用 <object> 先缓存 js,再执行:

<script type="text/javascript"> // 先cache js,再执行 var myJs = "http://example.com/myJs.js"; function cachejs(script_filename){ var cache = document.createElement('object'); cache.data = script_filename; cache.width = 0; cache.height = 0; document.body.appendChild(cache); } function loadjs(script_filename) { var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', script_filename); script.setAttribute('id', 'script_id'); script_id = document.getElementById('script_id'); if(script_id){ document.getElementsByTagName('head')[0].removeChild(script_id); } document.getElementsByTagName('head')[0].appendChild(script); } cachejs(myJs); loadjs(myJs); </script>

Page 49: Javascript编程技巧与优化

• 使用 jQuery 深度复制来重置对象,比如要在其它地方获取一个纯净的 oriObj 对象:

var pureObj = jQuery.extend(true, {}, oriObj); function someFunc() { oriObj = jQuery.extend(true, {}, pureObj); } someFunc(); // deal with oriObj

Page 50: Javascript编程技巧与优化

• 减少 js 依赖的方法:

1. 尽量不依赖别的 js 文件,插件或者引用都可以直接加到文件中,作为本地代码

2. 使用本地存储来解耦,比如 cookie3. 尽量不使用全局变量和全局函数,如必要,可以通过统一使

用一个全局变量来实现,比如: var myGlobal = { GLOBAL_CONSTANTS: "coco", "globalName": "kim", "globalFunc": function() { alert('haha'); } }

Page 51: Javascript编程技巧与优化

• 函数节流: // 睡一会儿 function sleep(milliSeconds){ var startTime = new Date().getTime(); while (new Date().getTime() < startTime + milliSeconds); }

var throttle = function(fn, delay) { // 定时阀 var timer = null; // 返回创建的函数 return function() { var that = this, args = arguments; clearTimeout(timer); timer = setTimeout(function() { fn.apply(that, args); }, delay); }; };

i = 0; var myFunc = function() { // 每 1.5秒加一点内容 sleep(1500); document.body.innerHTML += i + '<br />'; i++; }

window.onresize = throttle(myFunc, 100);

Page 52: Javascript编程技巧与优化

性能

Page 53: Javascript编程技巧与优化

• 尽量使用原生 javascript 方法

Page 54: Javascript编程技巧与优化

• 用逗号一次定义多个变量: var a = 1, b = 'hi', c = [1,3];

Page 55: Javascript编程技巧与优化

• 初始化数组或对象都可以只用一条语句:

var arr = new Array(); arr[0] = 1; arr[1] = 2; // 完全等同以下: var arr = [1, 2];

var obj = new Object(); obj.name = 'kim'; obj.age = 3; // 完全等同于一条字面量定义: var obj = { "name": 'kim', "age": 3 };

Page 56: Javascript编程技巧与优化

• 乘除 2 的操作都可以用位运算代替,比如: var i = 2 * 4; // 等价于 var i = 2 << 2;

Page 57: Javascript编程技巧与优化

• 三元运算符 “ ?:” 更简洁更快: var min = Math.min(a, b); // 慢 var min = a < b ? a : b; // 快

Page 58: Javascript编程技巧与优化

• 直接数组追加比 push 要快: arr.push(v); // 慢 arr[arr.length] = v; // 快

Page 59: Javascript编程技巧与优化

• 字符串连接: // 慢,创建了一个临时字符串 str += 'x' + 'y'; // 更快,更少内存 str += 'x'; str += 'y';

Page 60: Javascript编程技巧与优化

• 尽量不要用 for-in 来遍历对象。• for-in 会为对象的所有可枚举的属性创建一

个 list ,并且在进行枚举之前检查重复属性。

Page 61: Javascript编程技巧与优化

• 最快的数组循环: var i = arr.length - 1; if (i > -1) { do { // do something with arr[i] } while (--i >= 0); }

Page 62: Javascript编程技巧与优化

• 尽量不用 with 语句,容易出 bug 。• with 延长了作用域, js 编译时识别不了这

个附加作用域的,通常都可以直接用 obj.property 来代替。

Page 63: Javascript编程技巧与优化

• new String 的应用场景,如果需要多次调用字符串对象的属性时:

// 共创建 21 个变量,每次调用都会创建一个临时字符串变量 var s = '0123456789'; for (var i = 0; i < s.length; i++) { s.charAt(i); }

// 只创建一个对象 var s = new String('0123456789'); for (var i = 0; i < s.length; i++) { s.charAt(i); }

Page 64: Javascript编程技巧与优化

• 闭包:延长了作用域而且常驻内存。

Page 65: Javascript编程技巧与优化

• 对象、对象中的对象、闭包,在不用的时候就设为 null ,等待内存回收,特别是当对象是 Dom 元素的时候。

obj1.obj2 = new Foo(); obj1.dom3 = document.getElementById('id1'); // some operations ... obj1.obj2 = null; obj1.dom3 = null; obj1 = null;

Page 66: Javascript编程技巧与优化

• 尽量不用全局变量和全局函数:

1. 全局变量实际上是 2 个作用域,一个是当前 js 脚本,一个 windows 。

2. 在整个 js 运行周期内都占用内存,并不像局部变量,用完就可以被回收

Page 67: Javascript编程技巧与优化

• 函数内使用全局变量,尽量把全局变量变成局部变量,或者通过参数传入函数内部,以保证最短作用域链。

var foo = 'foo'; function bar() { var local = foo, dm = document; alert(local); dm.write(local); dm.write(local); }

Page 68: Javascript编程技巧与优化

• try-catch 是低性能的,切忌用在循环里,“变量 e” 是个额外开销

for (var i = 0; i < obj.length; i++) { try { test[obj[i]].property = somevalue; } catch(e) { ... } } 应该写在外面: try { for (var i = 0; i < obj.length; i++) { test[obj[i]].property = somevalue; } } catch(e) { ... }

Page 69: Javascript编程技巧与优化

• 更好的实践是根本不用 try-catch ,基本上大多数情况下都可以用 if 来代替。

• js 这种弱类型的语言,用 if 能解决很多问题。

Page 70: Javascript编程技巧与优化

• setTimeout 和 setInterval 应该直接传入 function :

setTimeout("alert('hihi')", 10); // 慢 setTimeout(function() { alert(‘hihi’); }, 10); // 快

Page 71: Javascript编程技巧与优化

• getElementById 是最快的,任何时候都是开发首选。

• 所有类型的 selector 都是可以用指定 id 来替代的。

Page 72: Javascript编程技巧与优化

• 尽量不使用 HTMLCollection 对象。• 比如

getElementByTagName 、 getElementsByName 、 document.images 、 document.forms 、jQuery('div') 等。

Page 73: Javascript编程技巧与优化

• innerHTML 和 outerHTML 的特点:

1. 很快,但不是所有元素都支持。 2. 需手动清除 innerHTML 里面 js 对象和属性绑定,优化内存

Page 74: Javascript编程技巧与优化

• 避免重复设置 innerHTML ,比如:

// 错误 for (var i = 0; i < 10; i++) { div.innerHTML += 'hi'; } // 正确 var htmltext = ''; for (var i = 0; i < 10; i++) { htmltext += 'hi'; } div.innerHTML(htmltext);

Page 75: Javascript编程技巧与优化

• 任何情况下,遍历节点都是性能杀手,应坚决避免,比如:

document.createNodeIterator

Page 76: Javascript编程技巧与优化

• eval == evil // 不解释

Page 77: Javascript编程技巧与优化

• 和 css 解耦:

1. 尽可能少的修改元素 style 属性 2. 不在 css 中使用 expression 3. 尽量通过修改 className 来修改样式 4. 通过 cssText 属性来设置样式值

// 进行了 4次重新渲染 el.style.color = 'red; el.style.height = '100px'; el.style.fontSize = '12px'; el.style.backgroundColor = 'white';

Page 78: Javascript编程技巧与优化

• 尽量不在元素中直接绑定事件处理,事件处理程序的本质:

<input onclick="alert(this)" />

1. 开辟内存,创建一个函数 2. 函数内部封装了对该对象的引用,即

this 对象 3. 创建了局部变量 event 事件对象 4. 每定义一个函数处理程序就是对 DOM 的

一次访问

Page 79: Javascript编程技巧与优化

• 解决 inline script 阻塞页面的方法,排名先后:

1. window.onload :并行下载,渲染无阻 2. setTimeout :并行下载,部分浏览器渲染

无阻 3. 移到底部:并行下载,但是渲染还是阻塞 4. defer :并行下载,部分浏览器支持

Page 80: Javascript编程技巧与优化

• 设置元素的 position 为 absolute 或 fixed ,可以使元素从 DOM 树结构中脱离出来独立的存在。

• 在元素的 position 为 static 和 relative 时,元素处于 DOM 树结构当中,当对元素的某个操作需要重新渲染时,浏览器会渲染整个页面。

Page 81: Javascript编程技巧与优化

• 页面重复渲染,即 reflow 和 repaint 发生的情景:

1. DOM 元素的添加、修改(内容)、删除 (Reflow + Repaint)2. 应用新的样式,或者修改任何影响元素外观属性的时候

(Reflow + Repaint)3. 仅修改 DOM 元素的字体颜色( Repaint)4. Resize 浏览器窗口、滚动页面( Reflow)5. 读取元素的部分属性( offsetLeft 、 offsetTop 、 offsetHeight 、 offsetWidth 、 scrollTop/Left/Width/Height 、 clientTop/Left/Width/Height 、 getComputedStyle() 、 currentStyle(in IE))(是的,读取属性也会引起 repaint!)

Page 82: Javascript编程技巧与优化

• Reflow :简单的说,就是位置、大小变了• Repaint :简单地说,就是字体、颜色变了

Page 83: Javascript编程技巧与优化

• 减少 reflow/repaint :

// 将元素的 display 设为 "none" ,完成修改后再把 display 改为原来的值

var dv = document.getElementById('divId'); dv.style.display = 'none'; dv.innerHTML += 'hi '; dv.innerHTML += 'kim'; dv.style.color = 'red'; dv.style.display = 'block';

Page 84: Javascript编程技巧与优化

• 减少 reflow/repaint :

// 使用 DocumentFragment 一次性创建多个 DOM节点 var span1 = document.createElement('span'); var span2 = document.createElement('span'); span1.appendChild(document.createTextNode("hi")); span2.appendChild(document.createTextNode("kim"));

var fragment = document.createDocumentFragment(); fragment.appendChild(span1); fragment.appendChild(span2);

var div = document.getElementById("divContainer"); div.appendChild(fragment);

Page 85: Javascript编程技巧与优化

• 层与渲染的关系:

// 创建了 2层 var newWidth = aDiv.offsetWidth + 10; // Read aDiv.style.width = newWidth + 'px'; // Write var newHeight = aDiv.offsetHeight + 10; // Read ,清空了 reflow 队列,导致新增一层

aDiv.style.height = newHeight + 'px'; // Write

// 只建了 1层 var newWidth = aDiv.offsetWidth + 10; // Read var newHeight = aDiv.offsetHeight + 10; // Read aDiv.style.width = newWidth + 'px'; // Write aDiv.style.height = newHeight + 'px'; // Write

Page 86: Javascript编程技巧与优化

• Javascript 终极优化 - 事件代理和委托 1. 减少 DOM 加载时间 2. 减少内存使用 3. 响应最快

Page 87: Javascript编程技巧与优化

/* 举一个实际应用中的例子:评论删除、回复、顶 */ "initListBindings": function() { var that = this; /* 代理 click 时间 */ jq('#' + config.cmtTarget).bind('click', function(event){ event.stopPropagation(); /* 停止冒泡 */ var target = jq(event.target); /* 获取正在访问的对象 */

switch (target.attr('class')) { case 'cmt_delete_link': /* 如果点击的是删除链接 */ that.openDelCommentPopup(); /* 打开删除对话框 */ break; case 'cmt_reply_link': /* 如果点击的是回复链接 */ that.openReplyPopup(); /* 打开回复框 */ break; case 'cmt_agree_link_em': /* 如果点击的是顶 */ target = target.parent(); case 'cmt_agree_link': /* 如果点击的是顶链接 */ that.ajaxIncNbAgree(event.target, ids[1], ids[2]); /* 执行“顶”动作 */ event.preventDefault(); // IE6 getJSON bug hack break; default: break; } }); },

Page 88: Javascript编程技巧与优化

实例吐槽

Page 89: Javascript编程技巧与优化

Javascript 优化无止境

Page 90: Javascript编程技巧与优化

Faq

Page 91: Javascript编程技巧与优化

谢谢!